Preorder drugiego tomu książki sekuraka: Wprowadzenie do bezpieczeństwa IT. -15% z kodem: sekurak-book
Bezpieczeństwo Windows. Autoryzacja od środka, czyli czego prawdopodobnie nie wiesz o ACL
Omawiając uprawnienia do obiektów (na przykład plików) zazwyczaj mówi się o ACL. Jest to skrót od Access Control List i wcale nie jest oczywiste co taka lista może zawierać. Poczynając od rozróżnienia DACL/SACL, poprzez wpisy warunkowe, aż po skrajnie rzadko występujące wynalazki jak atrybuty zasobu (Resource Attributes) opisywane przez struktury SYSTEM_RESOURCE_ATTRIBUTE_ACE. Na początek warto wiedzieć, że ACL (czyli lista) składa się z pewnej ilości ACE (Access Control Entries), czyli pojedynczych wpisów różnego typu.
Nawet pomijając bardziej zaawansowane aspekty, okazuje się, że najprostsza lista uprawnień może mieć swoje własne niuanse. Żeby je zaobserwować, należy zacząć od niskiego poziomu: każdy obiekt ma swój Security Descriptor – binarną strukturę opisującą przy pomocy poszczególnych bitów co danemu podmiotowi (użytkownikowi/grupie/itp., opisanemu oczywiście przy pomocy identyfikatora SID, a nie nazwy) wolno z danym obiektem zrobić. Znaczenie tych samych bitów będzie oczywiście inne w przypadku struktury Security Descriptor opisującej plik, niż w przypadku gałęzi rejestru, procesu, czy ETW. W niektórych miejscach w systemie można zobaczyć takie binarne opisy (na przykład w rejestrze, w HKLM\SYSTEM\CurrentControlSet\Control\WMI\Security, gdzie poszczególne wartości wprost są takimi deskryptorami.
Oczywiście taka binarna postać jest stosunkowo trudna do zrozumienia i modyfikacji przez człowieka, dlatego bywa konwertowana na odrobinę czytelniejszy, odpowiadający jej bezpośrednio opis tekstowy, zwany SDDL (Security Descriptor Definition Language). Konwersja taka wykonywana jest na przykład funkcją API ConvertSecurityDescriptorToStringSecurityDescriptorW()[1], możliwa oczywiście jest również konwersja odwrotna. W największym skrócie, istotne w kontekście niniejszego artykułu przypadki SDDL wyglądają na przykład tak: D:(A;; 0x1301bf;;; S-1-5-80-956009885-3418529649-1831039044-1853282631-2271498464) lub tak D:(A;;FA;;;BA)(A;;FR;;;WD)(D;;FA;;;LG). Postać pierwsza wprost odzwierciedla zawarte w deskryptorze bity i SID, postać druga zastępuje typowe wartości ich aliasami, zwykle dwuliterowymi skrótami, które wstawiane są automatycznie tam, gdzie dane bity udało się zinterpretować czy to jako znane uprawnienia[2], czy jako znany SID[3].
W przykładzie powyżej FA oznacza File Full Access, FR – File Read, BA – Builtin Admins, WD – Everyone (World), a LG – Local Guest. Cały ciąg SDDL (ten drugi) należy rozumieć jako: Discretionary Access Control (czyli uprawnienia) równe Allow Full dla Administratorów, Allow Read dla Wszystkich, Deny ALL dla konta Gościa. Przy odrobinie wprawy, typowe opisy w postaci SDDL są równie czytelne, jak to, co na zakładce „Security” wyświetla GUI Explorera. W nietypowych, mogą wydawać się zagmatwane, za to z pewnością są dużo bardziej precyzyjne i jednoznaczne.
Aplikowanie określonego SDDL na obiekt (na przykład plik) jest stosunkowo proste dla programisty, trochę bardziej złożone, jeżeli do dyspozycji są wyłącznie w budowane w system narzędzia. W ograniczonym zakresie nie jest to jednak bardzo trudne i zostanie omówione w dalszej części artykułu.
Poza rozumieniem samego deskryptora (albo na wyższym poziomie abstrakcji – listy ACL), do praktycznego użycia uprawnień niezbędne jest również „przetłumaczenie” ustawionych parametrów obiektu na to, co faktycznie dany użytkownik może zrobić z danym obiektem. Czy prawo odczytu pozwoli na stworzenie nowego pliku w danym folderze? Co stanie się, gdy użytkownik należy do kilku grup, którym nadane są różne poziomy uprawnień? A co, jeżeli uprawnienia pliku wynikają ze złożonej kombinacji uprawnień odziedziczonych z różnych folderów nadrzędnych i jeszcze, dodatkowo z uprawnień na samym obiekcie.
Oczywiście da się na takie pytania odpowiedzieć wyłącznie dzięki analizie ACL oraz tokenu użytkownika, jednak często jest to równie skomplikowane, co niepotrzebne. W praktyce, lepiej posłużyć się pewnego rodzaju symulacją „a co gdyby” oferowaną przez funkcję API AccessCheck()[4], której podaje się między innymi security descriptor, oraz dane użytkownika w postaci tokenu, a w rezultacie otrzymuje się zestaw uprawnień, które w takich warunkach będą możliwe do zrealizowania. Praktycznie podchodząc, można skorzystać z tej funkcjonalności na dwa sposoby: poprzez zakładkę Effective Access (opisaną dalej) lub działający z wiersza poleceń program Sysinternals AccessChk[5].
Po wstępie teoretycznym, można w praktyce spróbować zobaczyć jak to działa. W tym celu, należy:
1. Uruchomić polecenie cmd.exe i założyć folder, w którym przeprowadzane będą testy – md c:\my_acl_test
2. Zmienić bieżący folder – cd c:\my_acl_test
3. Założyć testowy plik echo test > pliktestowy.txt
4. Wyświetlić uprawnienia nowego pliku – icacls.exe pliktestowy.txt W wyniku działania programu widać, że na liście ACL znajdują się cztery pozycje, wszystkie odziedziczone („(I)”) z folderu nadrzędnego.
5. Wyświetlić uprawnienia nowego pliku z rozbiciem na poszczególne bity security descriptora – icacls.exe pliktestowy.txt /dbg
6. Przerobić odziedziczone uprawnienia na lokalnie nadane na własnej liście kontroli dostępu pliku – icacls.exe pliktestowy.txt /inheritance:d
7. Porównać uprawnienia z obowiązującymi wcześniej – icacls.exe pliktestowy.txt
8. Dodać uprawnienia dla gościa – icacls.exe pliktestowy.txt /grant Guest:F
9. Wyświetlić uprawnienia (flaga /dbg pozwoli je lepiej zrozumieć) – icacls.exe pliktestowy.txt /dbg
10. Zabronić dostępu dla gościa – icacls.exe pliktestowy.txt /deny Guest:F
11. Wyświetlić uprawnienia (flaga /dbg pozwoli je lepiej zrozumieć) – icacls.exe pliktestowy.txt /dbg
Z eksperymentu jasno widać, że typowe narzędzia działają w ten sposób, że zastępują istniejące prawa nowymi, zamiast dodawać kolejne, potencjalnie sprzeczne wpisy na liście. Wynika to zarówno z powodów zdroworozsądkowych, jak i z udokumentowanej, ale mało znanej specyfiki uprawnień: kolejne uprawnienia są ignorowane, jeżeli dane konto/grupa/SID (szerzej: Security Principal) powtarzają się na liście. Oczywiste jest jednak, że takie wewnętrznie sprzeczne uprawnienia da się opisać przy pomocy SDDL. Przykładowo będzie to: D:PAI(A;;FA;;;LG)(D;;FA;;;LG)(A;;FA;;;SY)(A;;FA;;;BA)(A;;FA;;;BU), gdzie P oznacza flagę Protected, a AI oznacza „auto inherited”, czyli brak dziedziczenia uprawnień folderu. Na początku SDDL jasno widać, że konto Gościa ma najpierw nadane uprawnienia, a zaraz potem – odebrane.
12. Ze względu na specyfikę narzędzia icacls, ustawienia przy pomocy SDDL nadaje się opisując je w pliku tekstowym (na przykład acl.txt), zawierającym najpierw nazwę pliku i w kolejnej linii jego SDDL. Ze względu na złożoność SDDL i wymagania narzędzia, plik taki najlepiej stworzyć poleceniem icacls.exe pliktestowy.txt /save acl.txt i następnie zmodyfikować go tak, aby zawierał D:PAI(A;;FA;;;LG)(D;;FA;;;LG)(A;;FA;;;SY)(A;;FA;;;BA)(A;;FA;;;BU)
13. Zaaplikowanie arbitralnej listy kontroli dostępu może wymagać praw administratora i po ustawieniu bieżącego folderu (cd \my_acl_test )ma postać icacls.exe . /restore acl.txt
14. Efekt działania jest prosty do zaobserwowania dzięki icacls.exe pliktekstowy.txt
Jak jasno widać, sama lista kontroli dostępu nie zabrania umieszczenia na niej sprzecznych pozycji, choć wymaga to trochę zachodu. Co ciekawe, samo narzędzie icacls.exe potrafi zauważyć, że coś jest nie tak i po wydaniu polecenia icacls.exe pliktestowy.txt /verify zgłasza „Ace entries not in canonical order.”.
Skutki tak nietypowej listy ACL można zaobserwować weryfikując faktyczne prawa dostępu Gościa. Wystarczy otworzyć folder w Explorerze, wyświetlić właściwości pliku pliktestowy.txt i na zakładce „Security” zaobserwować uprawnienia. Explorer wyświetla ostrzeżenie analogiczne do tego, które daje icacls.exe, jednak jest to poniekąd zamierzony efekt wcześniejszych działań. Po kliknięciu przycisku „Advanced” można znowu zobaczyć ostrzeżenie, z propozycją naprawy, nie należy z niej korzystać, jeżeli chcemy zaobserwować skutki celowo zmanipulowanej ACL. W oknie Advanced Security Settings można teraz skorzystać z linku „Select a user”, wybrać konto gościa i następnie kliknąć „View effective access”. W wyniku tej operacji, jasno widać, że przeprowadzona symulacja pozwala gościowi na dostęp do pliku, mimo tego, że razem z wpisem pozwalającym na taki dostęp, umieszczony został drugi – zabraniający. Warto posłużyć się opisanymi wyżej krokami żeby zaobserwować co stanie się w sytuacji, kiedy pozycje „Allow” i „Deny” zostaną zamienione miejscami. Analogiczny test przeprowadzić można wspomnianym wcześniej narzędziem Accesschk: accesschk.exe %computername%\guest pliktestowy.txt
Konkludując, stwierdzić można, że mimo mechanizmów utrudniających nietypowe manipulacje uprawnieniami, można doprowadzić do sytuacji, w której utworzona lista ACL zawiera ustawienia wzajemnie sprzeczne między sobą. Choć zachowanie systemu w takiej sytuacji jest udokumentowane i względnie proste do zweryfikowania, to jednak złożoność kontroli dostępu sprawia, że często zaskakuje nawet doświadczonych administratorów. Warto tu zwrócić uwagę, że w praktyce sprzeczne ustawienia wynikać mogą nie tylko z celowej manipulacji, ale i z sytuacji, kiedy poszczególne ACE dziedziczone są z kolejnych, coraz głębiej zagnieżdżonych folderów.
[1] https://learn.microsoft.com/en-us/windows/win32/api/sddl/nf-sddl-convertsecuritydescriptortostringsecuritydescriptorw
[2] https://learn.microsoft.com/en-us/windows/win32/secauthz/ace-strings
[3] https://learn.microsoft.com/en-us/windows/win32/secauthz/sid-strings
[4] https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-accesscheck
[5] https://learn.microsoft.com/en-us/sysinternals/downloads/accesschk
~Grzegorz Tworek
UWAGA! 15 maja 2023 odbędzie się druga część bezpłatnego szkolenia Windows (pierwsza przyciągnęła ponad 14 000 osób!): Poznaj bezpieczeństwo Windows. Część druga: lokalne uwierzytelnianie i autoryzacja w systemach Windows.
Zapisać można się tutaj: https://sklep.securitum.pl/poznaj-bezpieczenstwo-windows-2–lokalne-uwierzytelnianie-i-autoryzacja
Każdy uczestnik dostanie również dostęp do zapisu video z części pierwszej.
Zgodność logiki interfejsu z.wybranymi/wpisanymi rodzajami uprawnien.Exploit. .Analiza kodu wydaje sie relatywnie łatwa gdy kazdy rodzaj uprawnień w modelu uprawnien jest zwykłą zmienną/zmiennymi (modyfikacja to odczyt i zmiany)jako parametr do funkcji ze zdefiniowanymi operacjami. Gorzej gdy nie ma opisu operacji i/lub występuja dodatkowo
fragmenty kodu zmieniajace Logikę rozumianą bo widzianą po stronie interfejsu np osoby przydzielajacej uprawnienia.Jesli dany user nie ma opcji usun a okazalo sie ze zgnely dane to kto odpowiada za nadawanie.Pierwszy admin ?Czy to kryminal .Rejestry ktos usunał jak dowiesc faktycznego sprawce