Konferencja Mega Sekurak Hacking Party w Krakowie – 26-27 października!
Mikołajki z sekurakiem! od 2 do 8 grudnia!
Konferencja Mega Sekurak Hacking Party w Krakowie – 26-27 października!
Mikołajki z sekurakiem! od 2 do 8 grudnia!
Różnica pomiędzy uwierzytelnieniem (ang. authentication) i autoryzacją (ang. authorization) została już wyjaśniona w niejednej publikacji, więc tylko sobie przypomnijmy: proces uwierzytelnienia potwierdza, że na pewno jesteśmy osobą, za którą się podajemy, a autoryzacja sprawdza, do czego mamy dostęp jako ta osoba.
Intuicyjnym przykładem jest budynek firmy i pracownik, któremu wydano kartę dostępu, kiedy podpisywał umowę (uwierzytelnienie). Posiadacz tej karty może wejść do budynku, ale ma dostęp jedynie do działów, z którymi jest w jakiś sposób związany (autoryzacja). Do innych działów dostępu nie ma i jego karta nie zadziała.
Poniżej skupimy się na najważniejszym wycinku całej procedury logowania, związanym z LSA. Jeśli jednak kogoś interesuje trochę szersze spojrzenie na to, jak przebiega proces uwierzytelnienia użytkownika lokalnego podczas uruchomienia systemu, może zapoznać się z tym nagraniem: Windows Logon Process | Local User Account (momentami trudno jest zrozumieć akcent autora, ale dobrze opisane slajdy rekompensują niedogodności).
LSA (Local Security Authority) jest istotnym komponentem systemu Windows, który stanowi swojego rodzaju centrum bezpieczeństwa i odpowiada m.in. za:
Termin LSA bardziej odnosi się do konceptu, natomiast LSASS (Local Security Authority Subsystem Service) wskazuje na konkretny proces w systemie (lsass.exe), który odpowiada za zarządzanie dostępem. Dla uproszczenia, te dwa terminy były używane zamiennie podczas szkolenia, podobnie jak w tych notatkach.
Proces Winlogon (%SystemRoot%\System32\Winlogon.exe) jest odpowiedzialny za obsługę procesów logowania i wylogowania interaktywnego użytkownika, czyli m.in. za wyświetlenie ekranu logowania, przechwycenie wprowadzonych danych uwierzytelniających oraz wysłanie ich do LSA celem weryfikacji.
Przyjrzyjmy się teraz, jak z grubsza działa proces logowania użytkownika interaktywnego (do normalnej pracy z systemem) z użyciem nazwy konta/użytkownika i hasła. Poniższa lista skupia się na ogólnych aktywnościach tych dwóch komponentów (Winlogon oraz LSASS) i nie przedstawia kompletnej procedury, która jest dosyć mocno rozbudowana w systemie Windows.
Podsumowując, kiedy użytkownik poprawnie się zaloguje za sprawą procesu LSASS i otrzyma token dostępu, który zawiera m.in. informacje o uprawnieniach użytkownika, jest on (token) ostatecznie przypisywany głównemu procesowi explorer.exe oraz wszystkim procesom potomnym. Innymi słowy, procesy działają z uprawnieniami zalogowanego użytkownika.
LSA może zostać poproszony o wygenerowanie nowego tokena dla danego procesu, w kontekście innego użytkownika – tak działa mechanizm Run As. W takim przypadku należy oczywiście podać prawidłowe dane uwierzytelniające docelowego użytkownika. W WinAPI do tego celu można użyć funkcji CreateProcessWithLogonW.
Okazuje się, że opisany wyżej proces logowania można rozszerzyć o dodatkowe funkcjonalności. Są to obszary mało udokumentowane, ale autor szkolenia (Grzegorz Tworek) zadał sobie trud zbadania tych mechanizmów i podzielił się nimi w trakcie szkolenia.
Generalnie, w pewnym momencie zarówno Winlogon jak i LSASS wykonują kilka czynności pobocznych na podstawie kodu zdefiniowanego w określonych bibliotekach DLL i nic nie stoi na przeszkodzie, żeby napisać i zarejestrować swoje biblioteki (zakładając oczywiście, że mamy do tego odpowiednie uprawnienia).
W pewnym momencie procesu logowania, Winlogon sprawdza w rejestrze czy istnieje klucz HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\mpnotify. Jeśli tak, to będzie próbował uruchomić plik wykonywalny podany w wartości tego klucza.
Kiedy takiego wpisu brakuje (jak to jest domyślnie), to uruchamiany jest wbudowany proces %systemroot%\System32\mpnotify.exe, odpowiedzialny za dostarczanie w czasie rzeczywistym powiadomień związanych z bezpieczeństwem.
Kiedy proces mpnotify wystartuje, odczytuje ze swojej gałęzi rejestru biblioteki DLL, które powinny być załadowane w jego kontekście (tzw. notification packages). Idea stojąca za tym mechanizmem polega na powiadomieniu określonych komponentów systemowych Windows o zdarzeniach związanych z uwierzytelnieniem. Następnie otwierany jest kanał komunikacji LRPC (Lightweight Remote Procedure Call) z Winlogon, który wysyła nim m.in. dane uwierzytelniające do mpnotify, a ten przekazuje później dane do załadowanych DLL-ek.
Gdyby udało nam się podstawić naszą, spreparowaną bibliotekę DLL, moglibyśmy przechwycić dane przesłane przez Winlogon, w tym login i hasło użytkownika, który właśnie próbuje się uwierzytelnić.
Załóżmy więc, że chcemy przejąć hasło innego administratora w systemie. Moglibyśmy napisać własny proces mpnotify i następnie umieścić ścieżkę do naszej binarki w rejestrze, ale jest prostszy sposób. Domyślny proces systemowy mpnotify.exe również przechowuje w rejestrze informacje o DLL-kach, którym przekazuje dane otrzymane od Winlogon. Można je znaleźć w kluczu HKLM\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order\ProviderOrder. Wystarczy więc, że napiszemy własną bibliotekę DLL udającą Network Provider i dodamy ją do tej listy w rejestrze.
Cały proces został przedstawiony na tym nagraniu (również od Grzegorza): How winlogon.exe shares the cleartext password with custom DLLs. Przykładowy kod źródłowy znajduje się w repozytorium: gtworek/PSBits/PasswordStealing/NPPSpy. Znajdziemy tutaj kod biblioteki, która zapisuje przechwycone hasło do pliku tekstowego oraz skrypt PowerShell dodający nasz fake’owy network provider do rejestru. Aby kod zadziałał musimy ponownie wywołać proces winlogon.exe, więc powinniśmy się jeszcze raz zalogować.
Opisany wyżej mechanizm, uwarunkowany wsteczną kompatybilnością, może stanowić pewnego rodzaju lukę w bezpieczeństwie, choć należy pamiętać, że do jego wykorzystania potrzebne są uprawnienia administracyjne. Na wszelki wypadek możemy raz na jakiś czas skontrolować listę providerów sieciowych w rejestrze za pomocą skryptu PS (również z powyższego repozytorium): Get-NetworkProviders.ps1.
LASS jest procesem nieźle zaprojektowanym i dobrze zaimplementowanym, więc trudniej jest go zaatakować. Okazuje się jednak, że można wykorzystać podobny myk, jak ten opisany wyżej w przypadku Winlogon i podstawić swoją bibliotekę do filtrowania haseł (Password Filter).
Wspomniane filtry to nic innego jak biblioteki DLL, wywoływane przez LSA w chwili, gdy użytkownik chce zmienić hasło. Ich zadaniem jest wymuszenie odpowiedniej polityki (np. hasło nie może być krótsze niż 12 znaków) oraz powiadomienie o fakcie zmiany hasła.
Kod biblioteki DLL udającej taki filtr hasła można znaleźć tutaj: gtworek/PSBits/PasswordStealing/PSPY.c. Przechwytuje ona nowe hasło użytkownika, otrzymane od LSA i zapisuje je w pliku tekstowym. Następnie, zawsze zwraca informację, że nowe hasło spełnia wymagane kryteria.
Proces instalacji jest bardzo prosty: wystarczy umieścić skompilowaną DLL-kę w katalogu %systemroot%\System32; dodać (nie nadpisać) nazwę pliku do klucza rejestru HKLM\SYSTEM\CurrentControlSet\Control\Lsa\Notification Packages oraz upewnić się, że w ustawieniach systemowych jest włączona opcja wymuszania odpowiedniej złożoności hasła. Cały proces jest opisany w dokumentacji: Installing and Registering a Password Filter DLL.
Zostało tylko poczekać, aż jakiś użytkownik systemu będzie chciał zmienić swoje hasło. Oczywiście należy pamiętać, że możemy to traktować jako lukę w zabezpieczeniach, ale nie damy rady jej wykorzystać jeśli nie posiadamy uprawnień administracyjnych.
Token dostępu (ang. access token) jest specjalną strukturą danych, która zawiera informacje o tzw. kontekście bezpieczeństwa (ang. security context) procesu lub wątku. Informacje w nim zawarte to m.in. tożsamość konta użytkownika, jego przynależność do określonych grup oraz uprawnienia jakie posiada.
Token jest wydawany przez LSA w chwili, gdy użytkownik zostanie poprawnie uwierzytelniony. Każdy proces uruchomiony w imieniu użytkownika posiada kopię tokena wydanego temu użytkownikowi. Więcej na temat tokenów można znaleźć w artykule: Introduction to Windows tokens for security practitioners | Elastic Blog.
Wartość tokena można podejrzeć na kilka sposobów:
Przeglądając listę procesów w różnych narzędziach, jak choćby wspomniany wcześniej Process Hacker, znajdziemy informacje o użytkownikach tych procesów. To co może rzucić się w oczy, to fakt, że część tych nazw nie wskazuje na fizycznie istniejące konto bądź domenę w systemie – na przykład użytkownik NT AUTHORITY\LocalService z zadziwiająco krótkim SID-em: S-1-5-19 bądź grupa NT AUTHORITY\Local account z SID-em S-1-5-113.
Jest to przykład jednego z tzw. Well-known SIDs, czyli globalnych identyfikatorów wskazujących na predefiniowanych/wbudowanych (generycznych) użytkowników oraz grupy. Oznacza to, że na różnych maszynach znajdziemy identyczne wartości SID dla wspomnianych użytkowników bądź grup. Pozwala to na zachowanie pewnych standardów w mechanizmach zabezpieczających, stosowanych w systemach z rodziny Windows.
W systemie Windows nie istnieje procedura aktualizacji tokenów, po wydaniu przez LSA. Oznacza to, że jeśli zajdzie taka potrzeba, to należy zalogować się ponownie, żeby otrzymać nowy, zaktualizowany token. Jeśli jednak mamy uprawnienia administracyjne (bądź nasz użytkownik posiada przywilej SeDebugPrivilege), możemy sobie pożyczyć (lub mówiąc kolokwialnie podkraść) token od innego procesu.
Można to zrobić np. za pomocą wspomnianej wyżej aplikacji Process Hacker. Załóżmy, że potrzebujemy na chwilę uruchomić proces z uprawnieniami konta NT AUTHORITY\SYSTEM. Znajdujemy na liście procesów taki, który działa w kontekście wspomnianego konta i z menu kontekstowego (prawy przycisk myszy) wybieramy kolejno: Miscellaneous -> Run as this user… i wybieramy proces, który chcemy uruchomić z nowymi uprawnieniami.
Inny sposób to skorzystanie z narzędzia PsExec: psexec -i -d -s cmd.exe. Polecenie uruchamia nowy proces cmd.exe w trybie interaktywnym (-i); bez czekania na jego zakończenie (-d) oraz w kontekście konta systemowego, z rozszerzonymi uprawnieniami (-s). Oczywiście sam PsExec powinien być uruchomiony z prawami administratora, żeby udało się uzyskać token konta systemowego.
Jeśli kogoś interesuje, jak mechanizm przejmowania tokena działa pod spodem, może zapoznać się z tym artykułem: APT techniques: Access Token manipulation. Token theft. Simple C++ example. – cocomelonc.
Zdając sobie sprawę z istnienia wspomnianych wcześniej well-known SIDs oraz wirtualnych nazw grup i użytkowników, dla których nie ma fizycznego konta w systemie, niektórzy mogą się zastanawiać, czy da się w takim razie wygenerować token zawierający dowolną, zmyśloną nazwę domeny i użytkownika. Autor szkolenia (Grzegorz) nie tylko się zastanowił, ale też i udowodnił, że jest taka możliwość.
Posiadając odpowiednie uprawnienia, możliwe jest wygenerowanie tokena na życzenie, podobnie jak to robi Winlogon. Demonstruje to przykładowy kod RunAsVA.c, który tworzy nową, zmyśloną tożsamość (w tym przypadku nazwa domeny i użytkownika to po prostu emotikonki) wraz z własnymi wartościami SID, a następnie prosi LSA o wygenerowanie tokena dostępu dla tego użytkownika.
Generowanie tokena odbywa się za sprawą funkcji LogonUserExExW. Ponieważ zwrócony token jest typu Impersonation (w uproszczeniu: do użycia jedynie przez wątki), należy skonwertować go na typ Primary (podstawowy typ wydawany użytkownikom i przypisywany procesom) poprzez jego duplikację: DuplicateTokenEx. Zduplikowany token typu Primary (zawierający nazwę zmyślonego konta) może być teraz użyty do utworzenia nowego procesu.
Żeby wykonać powyższą sztuczkę, potrzebne jest uprawnienie SeTcbPrivilege, które posiada konto LocalSystem, ale wiemy już przecież jak pożyczyć sobie odpowiedni token za pomocą narzędzi Process Hacker lub PsExec.
W tym samym repozytorium znajdziemy podobny przykład z wygenerowaniem tokena dla własnej, wirtualnej nazwy konta, ale tym razem z uprawnieniami TrustedInstaller.
Token dostępu posiada również atrybuty (Process Hacker: R-click -> Properties -> Token -> Advanced -> Attributes), do których można wrzucić dodatkowe informacje. Od jakiegoś czasu system Windows dodaje tam wpisy z identyfikatorem procesu (TSA://ProcUnique), ale trudno powiedzieć czy jest to gdzieś rzeczywiście wykorzystywane.
Okazuje się, że my również możemy coś tam dodać, jeśli czujemy taką potrzebę. Autor szkolenia nie udostępnił w tym przypadku kodu źródłowego, ale uchyla rąbka tajemnicy, jak tego dokonać, na Twitterze.
Przywileje/uprawnienia (ang. privileges) określają pewne działania, które można wykonać w danym systemie operacyjnym. W zależności od konta będziemy mieli inny zestaw przywilejów: zwykły użytkownik posiada mniej uprawnień niż administrator, a ten z kolei na ma tych, które posiada konto LocalSystem.
Poza tym zestaw uprawnień może znacząco się różnić w przypadku różnych obiektów systemowych czy nawet samych systemów. Przykładowo, zwykły użytkownik w Windows 11 posiada uprawnienie do wyłączenia komputera (SeShutdownPrivilege), ale nie ma takiej możliwości (w domyśle) w systemach z rodziny Windows Server.
Część z tych przywilejów można wykorzystać w ciekawych celach. W repozytorium Priv2Admin znajdziemy listę popularnych uprawnień oraz informacje o tym, w jaki sposób dane uprawnienie ma wpływ na działania systemu i czy stanowi potencjalne zagrożenie. Kolumna Impact wskazuje na to, co można uzyskać kiedy posiadamy wybrany przywilej jako zwykły użytkownik. Dodatkowo, w tabeli znajdziemy informacje o potencjalnych sposobach wykorzystania danego przywileju.
Ciekawsze przykłady:
Przywileje opisane powyżej są lub powinny być w domyśle nadane jedynie zaufanym użytkownikom, czyli głównie administratorom. Żeby atak privilege escalation był skuteczny, te uprawnienia musiałyby być nierozważnie przypisane zwykłemu użytkownikowi.
Jeśli konto ma już przypisane uprawnienia, to bez problemu można je włączać (ang. enable) i wyłączać (ang. disable). Z punktu widzenia bezpieczeństwa nie ma to znaczenia, ponieważ posiadacz danego przywileju może sobie nim swobodnie zarządzać. Tutaj bardziej chodzi o dodatkową ochronę przed niezamierzonym błędem i świadome korzystanie z wybranych uprawnień (szczególnie przez programistów).
Windows posiada wbudowane narzędzie secpol.msc do zarządzania uprawnieniami z użyciem interfejsu GUI. W tej aplikacji punktem wyjściowym są przywileje, a nie konta użytkowników (tzn. do wylistowanych przywilejów przypisujemy konta, a nie odwrotnie).
W secpol.msc można zarządzać nie tylko przywilejami, w dosłownym tego słow znaczaniu, ale też politykami dostępu (ang. policies). Na przykład, pozycja Security Settings -> Local Policies -> User Rights Assignment -> Access this computer from the network nie jest stricte uprawnieniem, a polityką dostępu, ponieważ jest to ustawienie weryfikowane przez LSA, zanim jeszcze zostanie wygenerowany token dostępu z wpisanymi przywilejami.
Wszystkie uprawnienia wraz z ich właścicielami są zapisane w bazie SAM (Security Account Manager), będącej częścią rejestru systemowego i przechowywanej w pliku %SystemRoot%\System32\Config\SAM. Dostęp do tego pliku jest mocno utrudniony, ponieważ jest on stale używany przez proces LSASS.
Jeśli jednak jesteśmy wystarczająco zdeterminowani, możemy zmodyfikować bazę SAM bezpośrednio, przeprowadzając tzw. atak offline. Dokładniejszy opis techniki, wraz z przykładami, jest dostępny w repozytorium OfflineSAM. Przykłady pokazują w jaki sposób nadać uprawnienia administratora wszystkim kontom z bazy SAM oraz jak można dodać nowego użytkownika z uprawnieniami admina.
Praktycznie każdy obiekt w systemie Windows posiada tzw. security descriptor, który jest strukturą binarną przechowującą informacje związane z bezpieczeństwem danego obiektu (głównie te związane z dostępem). Przykład takiej struktury (w postaci binarnej) znajdziemy rejestrze, kiedy sprawdzimy wpis dla usługi gpsvc (Group Policy Client): HKLM\SYSTEM\CurrentControlSet\Services\gpsvc\Security\Security.
Na szczęście deskryptor posiada również postać tekstową, która jest bardziej zrozumiała dla człowieka, a konkretnie jest opisany specjalnym językiem SDDL (Security Descriptor Definition Language).
Deskryptor SDDL dla naszej przykładowej usługi możemy sprawdzić wydając polecenie w CMD: sc.exe sdshow gpsvc, na razie jako zwykły użytkownik. Wynik może wyglądać następująco:
| D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;CCLCSWLOCRRC;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU) |
Dosyć enigmatyczne na pierwszy rzut oka, ale spróbujmy to rozpracować:
W zależności od uprawnień użytkownika, deskryptor może zawierać trochę inne informacje. Na przykład, wykonując powyższe polecenie jako administrator (lub ktoś z przywilejem SaSecurityPrivilege), dostaniemy trochę bardziej rozbudowany string:
| D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;CCLCSWLOCRRC;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)S:(AU;SAFA;DCSDWDWO;;;WD) |
Zwróćmy uwagę na dodatkowy wpis ACE rozpoczynający się od S:, czyli SACL (System Access Control List), który określa jakiego typu czynności czy próby dostępu powinny być monitorowane i logowane (innymi słowy: w jaki sposób patrzymy użytkownikom systemu na ręce).
Podany wyżej przykład pokazuje SD dla obiektu będącego usługą systemową Windows, ale inne obiekty (np. pliki czy klucze rejestru) prawdopodobnie będą posiadały deskryptory bezpieczeństwa innego rodzaju. To od typu obiektu zależy co można z nim zrobić i nawet jeśli deskryptory różnych obiektów mają podobne bity, to mogą one mieć zupełnie inne znaczenie.
Listę obiektów systemowych zarządzanych przez Object Manager da się sprawdzić za pomocą narzędzia WinObj. Przy okazji warto wspomnieć, że w systemie Windows istnieje pewna klasa obiektów, które nie są zarządzane przez Object Manager, a przez inne (dedykowane) byty systemowe. Na przykład:
Deskryptory plików (podobnie jak deskryptory kluczy rejestru) można sprawdzić i zmodyfikować za pomocą systemowego UI, wchodząc we właściwości pliku i zakładkę Security. Jednakże ten interfejs jest bardzo mocno ograniczony i nie nadaje się do poważniejszych rzeczy, dlatego lepiej zajrzeć trochę głębiej, klikając przycisk Advanced.
Tutaj widzimy szczegółowe informacje o poszczególnych uprawnieniach oraz skąd zostały odziedziczone. Poza tym widzimy je w prawidłowej kolejności. Wybierając wpis (permission entry) i wchodząc w jego szczegóły, widzimy wizualną reprezentację tego, co prezentuje string SDDL.
Czasami trudno jest zweryfikować jakie ostateczne uprawnienia ma dany użytkownik, kiedy ten należy do wielu grup – wtedy część odziedziczonych uprawnień jest niewidoczna na pierwszy rzut oka. Zamiast jednak skakać po grupach, można skorzystać z zakładki Effective Access (dostępnej w zaawansowanych opcjach omawianego właśnie UI) i zobaczyć jak wyglądają efektywne (ostateczne) uprawnienia wybranego konta.
Inne narzędzia:
Narzędzia pokazujące efektywny dostęp do pliku często są w stanie wskazać problemy z uprawnieniami, ponieważ okazuje się, że system Windows daje takie możliwości ich konfiguracji, że czasami można nieźle namieszać (niechcący bądź intencjonalnie). Dobrze zostało to opisane w artykule Bezpieczeństwo Windows. Autoryzacja od środka, czyli czego prawdopodobnie nie wiesz o ACL.
Sytuacją, która może wydawać się trochę dziwna, jest brak dostępu do jednego z katalogów w całej ścieżce do pliku. Załóżmy, że użytkownik chce się dostać do pliku C:\A\B\C\file.txt – ma uprawnienie do odczytu zawartości docelowego pliku oraz wszystkich katalogów z podanej ścieżki, oprócz katalogu B. Mimo to, użytkownik będzie w stanie odczytać plik file.txt i jest to możliwe dzięki wymienionemu już wcześniej przywilejowi SeChangeNotifyPrivilege (Bypass traverse checking).
Jeśli ktoś jest zainteresowany tematem warunkowych ACL (np. możliwość odczytania zawartości pliku jedynie przez wybrane aplikacje), to może zapoznać się z tą prezentacją: How to use conditional ACEs to get a file one app can open, while another one cannot.
łał :o
To może jeszcze poproszę parę słów o CredentialUIBroker.exe i jego odsłonach “OK” oraz “user/pass”. Kiedy się pojawia, jak zrobić, żby się nie pojawiał itd :-)
Czyli weryfikacja zainstalowana na jakimś urządzeniu jest w miarę bezpieczna? Ostatnio co prawda FB zmienił zabezpieczenia z lepszych na gorsze (wymagają włączenia kodów sms) ale cały portal jest dobrym źródłem informacji dla hakerów i pełen syfu.
Szacun i wielkie dzięki za ten artykuł!