Rejestrowanie bloków skryptów

https://chacker.pl/

Rejestrowanie bloków skryptów służy do rejestrowania, kiedy wykonywane są bloki skryptów, co zapewnia większą głębię w tym, co jest wykonywane. Począwszy od programu PowerShell v5.0, rejestrowanie bloków skryptów dostarcza wielu danych o potencjalnie podejrzanych zdarzeniach, aby dać ludziom zajmującym się analizą kryminalistyczną coś do zrobienia. Rejestrowane elementy obejmują skrypty uruchomione za pomocą opcji encodedcommand, a także wszelkie podstawowe zaciemnianie. Dlatego po włączeniu rejestrowania bloków skryptów obrońcy prawdopodobnie będą mieli dodatkowe informacje na temat tego, co robiłeś. Jest to lepsze rozwiązanie dla obrońców niż rejestrowanie modułów, ponieważ wyróżnia rzeczy, które prawdopodobnie byłyby dla Ciebie ważne z punktu widzenia analizy kryminalistycznej, a jednocześnie nie powoduje tak dużego obciążenia analizą dziennika.

 

Rejestrowanie modułów

https://chacker.pl/

Rejestrowanie modułów umożliwia szereg funkcji dotyczących sposobu ładowania skryptów i podstawowych informacji o tym, co zostało wykonane. Obejmuje to, jakie moduły i zmienne zostały załadowane, a nawet niektóre informacje o skrypcie. Rejestrowanie to znacznie zwiększa szczegółowość podczas uruchamiania skryptów programu PowerShell i może być przytłaczające dla administratora. Rejestrowanie modułów jest dostępne od wersji PowerShell v3.0 i nie jest domyślnie włączone, więc aby uzyskać to rejestrowanie, należy włączyć obiekt zasad grupy (GPO) w systemach. Chociaż ten typ rejestrowania zwiększa widoczność tego, co zostało uruchomione, w większości przypadków nie zapewnia faktycznego kodu, który został uruchomiony. Dlatego też w przypadku dochodzenia kryminalistycznego ten poziom rejestrowania jest nadal niewystarczający. Będzie jednak naprowadzał śledczych na typy rzeczy, które robiłeś, chociaż szczegóły prawdopodobnie nie zostaną zarejestrowane.

Rejestrowanie w programie PowerShell

https://chacker.pl/

We wcześniejszych wersjach programu PowerShell (przed v4.0) dostępnych było tylko kilka opcji rejestrowania. Pozwalało nam to działać bez tworzenia wielu alertów dziennika podczas ładowania programu PowerShell, a także bardzo utrudniało osobom zajmującym się analizą kryminalistyczną ustalenie, co robiliśmy. Rejestrowanie rejestrowało tylko fakt załadowania programu PowerShell. W nowszych wersjach programu PowerShell dostępne są dodatkowe opcje zwiększające rejestrowanie w programie PowerShell. Z tego powodu ukierunkowanie na najnowszą wersję systemu Windows może zdradzić więcej informacji o tym, co robisz, niż w starszych wersjach.

UWAGA: Omawiamy tylko kilka aspektów rejestrowania w programie PowerShell, które mogą mieć wpływ na wykrywanie włamań. Aby uzyskać więcej informacji, dodaliśmy odniesienie z FireEye, które bardziej szczegółowo opisuje różne opcje i wyjaśnia, jak je włączyć.

Życie z ziemi

https://chacker.pl/

Kiedy mówimy o „życiu z ziemi”, mamy na myśli korzystanie z narzędzi już obecnych w systemach w celu dalszego wykorzystania luk. Jest to cenne, ponieważ zawsze, gdy dodajemy coś do systemu, zwiększamy prawdopodobieństwo wykrycia. Co więcej, gdy zostawiamy narzędzia, pomaga to ujawnić nasze taktyki, techniki i procedury (TTP), dzięki czemu łatwiej jest znaleźć naszą aktywność w innych systemach. Gdy żyjemy z ziemi, możemy zostawić mniej artefaktów i ograniczyć narzędzia, które musimy przenosić z systemu do systemu. PowerShell jest przydatny jako już istniejące narzędzie w systemie, ponieważ daje nam możliwość łatwego pisania skryptów, a także obejmuje integrację z .NET, więc prawie wszystko, co możemy napisać w .NET, możemy napisać w PowerShell. Oznacza to, że możemy wyjść poza podstawowe skrypty i wchodzić w interakcje z funkcjami jądra i nie tylko. Daje nam to dodatkową elastyczność, która normalnie wymagałaby użycia oddzielnych programów. Jedną z głównych zalet PowerShell jest to, że może on korzystać z opcji przeglądarki Internet Explorer, więc takie rzeczy jak obsługa proxy są wbudowane w PowerShell. W rezultacie możemy używać wbudowanych bibliotek internetowych do zdalnego ładowania kodu, co oznacza, że ​​nie musimy ręcznie pobierać żadnego kodu do systemu docelowego. Dlatego gdy ktoś spojrzy na oś czasu systemu plików, te pobrania ze stron internetowych nie będą widoczne, co pozwoli nam być jeszcze bardziej dyskretnym.

Dlaczego PowerShell

https://chacker.pl/

Chociaż język PowerShell był błogosławieństwem dla automatyzacji systemów Windows, daje hakerom przewagę. PowerShell zapewnia nam dostęp do niemal wszystkich funkcji systemu Windows w sposób programowy. Jest rozszerzalny i może być używany do administrowania usługą Active Directory, systemami poczty e-mail, programem SharePoint, stacjami roboczymi i nie tylko. PowerShell zapewnia nam dostęp do bibliotek .NET z poziomu interfejsu skryptowego, co czyni go jednym z najbardziej elastycznych narzędzi, których można używać w środowisku Windows.

Wykorzystanie PowerShell

https://chacker.pl/

Większość systemów korporacyjnych opiera się na systemie Windows, dlatego ważne jest, abyśmy dobrze znali narzędzia dostępne w systemach Windows. Jednym z najpotężniejszych z tych narzędzi jest PowerShell. W tym rozdziale dowiesz się, co sprawia, że ​​PowerShell jest tak potężnym narzędziem, i przyjrzymy się kilku sposobom jego wykorzystania jako części naszego zestawu narzędzi do eksploatacji luk.

Podsumowanie

https://chacker.pl/

Jądro systemu Windows może być trudne, ale możliwe do opanowania przy odpowiednich zasobach i pod ręką debugera. Nieudokumentowana natura samego jądra sprawia, że ​​badanie lub wykorzystywanie go jest jeszcze bardziej czasochłonne. W laboratoriach skonfigurowałeś debugowanie jądra, wybrałeś znany podatny sterownik jądra jako cel, wykonałeś inżynierię wsteczną sterownika, napisałeś narzędzie do interakcji ze sterownikiem, a następnie napisałeś exploit LPE, wykorzystując kradzież tokenów za pośrednictwem funkcjonalności w sterowniku. Miejmy nadzieję, że dało Ci to punkt wyjścia do rozpoczęcia dalszych badań jądra!

 

Pisanie exploita jądra

https://chacker.pl/

Kontynuując pracę nad naszym kodem exploita, musimy znaleźć bazę jądra i symbol PsInitialSystemProcess. Ponieważ zakładamy, że mamy dostęp na poziomie użytkownika do tego exploita, możemy poprosić system, aby powiedział nam, gdzie znajduje się baza każdego załadowanego sterownika za pomocą funkcji EnumDeviceDrivers, a następnie możemy uzyskać nazwę sterownika pod każdym adresem bazowym za pomocą funkcji GetDeviceDriverBaseNameA:

Tutaj jest sporo do rozpakowania! Pierwsze wywołanie numDeviceDrivers umieszcza wymagany rozmiar bufora (w bajtach) w needed (1). Następnie bufor jest przydzielany do przechowywania oczekiwanego wyjścia (2), a bufor ten jest wypełniany poprzez drugie wywołanie EnumDeviceDrivers (3). Następnie adresy bazowe są iterowane, a nazwa każdego z nich jest pobierana poprzez GetDeviceDriverBaseNameA (4). Namebuf ma długość 260 bajtów (5), co możesz rozpoznać jako MAX_PATH; powinno to wystarczyć, aby zmieścić nazwę sterownika. Jeśli nazwa pasuje do ntoskrnl.exe (6), wówczas baza w tej bieżącej iteracji może zostać zwrócona jako baza jądra (7). Ponownie, ta technika działa tylko dla LPE o średniej integralności lub lepszej. Zdalne i/lub eksploity o niskiej integralności muszą znaleźć inny sposób na uzyskanie wskaźnika _EPROCESS, np. poprzez wyciek pamięci i dowolny prymityw odczytu. Na koniec możemy skonstruować eksploit. Utwórz plik w katalogu src/bin swojego projektu o nazwie exploit.rs i dodaj następujące elementy:

W głównych nawiasach najpierw wywołaj funkcję open_dev, aby uzyskać HANDLE do urządzenia. Ponieważ zadeklarowaliśmy tę funkcję jako unsafe, wywołanie musi zostać opakowane w blok unsafe:

Jako ćwiczenie wstaw po wywołaniu LoadLibraryA następujący kod:

Spowoduje to wstrzymanie programu do momentu naciśnięcia klawisza, co da Ci czas na zbadanie programu. Zdefiniuj to jako funkcję, jeśli chcesz wstrzymać program w wielu punktach. Uruchom program za pomocą cargo run –bin exploit. Następnie załaduj Sysinternals Process Explorer, znajdź proces exploita i otwórz dolny panel widoku DLL. Wyszukaj „ntoskrnl.exe” i zwróć uwagę, że adres bazowy jest adresem w trybie użytkownika. Obraz jądra, do którego odwołujesz się jako hkernel, jest tą kopią w trybie użytkownika, a nie tą w działającym jądrze. Aby uzyskać adres PsInitialSystemProcess w działającym jądrze, najpierw znajdziemy względny adres wirtualny (RVA) symbolu. RVA to po prostu przesunięcie symbolu od podstawy obrazu. Aby je obliczyć, możemy odjąć adres bazowy modułu (hkernel) (2) od adresu PsInitialSystemProcess wewnątrz kopii jądra w trybie użytkownika. W trybie użytkownika GetProcAddress (1) może zostać użyte do znalezienia dowolnego wyeksportowanego symbolu w załadowanym obrazie PE, więc możemy użyć go do znalezienia adresu symbolu. Aby uzyskać adres, którego potrzebujemy w działającym jądrze, dodaj obliczony RVA do wartości zwracanej przez get_kernel_base (3). Ponieważ każda operacja w tym procesie wymaga znacznika unsafe, możemy uwzględnić go w tym samym bloku i zakończyć go adresem PsInitialSystemProcess w działającym jądrze:

UWAGA: Brakujący średnik na końcu ostatniego wiersza, w punkcie (3), nie jest literówką i jest zamierzony. W Rust wiersz, który nie kończy się średnikiem, jest zwracany z tego bloku. W tym przypadku wartość ostatniego wiersza jest umieszczana w zmiennej lpisp. Ponieważ wartość w lpisp jest po prostu wskaźnikiem do PsInitialSystemProcess, następną rzeczą, którą musimy zrobić, jest wykorzystanie dowolnego prymitywu odczytu, aby pobrać adres wewnątrz niego:

Używa to dowolnego odczytu jądra, aby uzyskać adres struktury _EPROCESS reprezentującej proces SYSTEM (PID 4). Możesz chcieć sprawdzić, czy wartość jest poprawna. Aby to zrobić, dodaj polecenie print i pauzę (jak opisano wcześniej), a następnie zrzuć wartość wewnątrz PsInitialSystemProcess w debugerze za pomocą polecenia dq nt!PsInitialSystemProcess L1. Ponieważ kradniemy tokeny z procesu SYSTEM, następnym krokiem jest odczytanie pola Token _EPROCESS za pomocą dowolnego odczytu. W tym momencie powinieneś sprawdzić przesunięcia od podstawy struktury _EPROCESS dla pól UniqueProcessId, ActiveProcessLinks i Token. Można to łatwo zrobić w debugerze jądra za pomocą następującego polecenia:

Następnie zdefiniuj te stałe w górnej części pliku exploits.rs

Teraz odczytaj token SYSTEM z procesu systemowego za pomocą dowolnego wskaźnika:

Następny krok jest nieco bardziej skomplikowany, ponieważ teraz musimy przejść listę procesów przez podwójnie łączoną listę ActiveProcessLinks, aby znaleźć aktualnie wykonywany proces. Przechodzenie listy procesów jest nieco trudne, ponieważ lista ActiveProcessLinks nie wskazuje na początek następnego procesu; zamiast tego wskazuje na strukturę ActiveProcessLinks w następnym procesie! Aby to rozwiązać, musimy odczytać wartość w ActiveProcessLinks (2), a następnie odjąć przesunięcie ActiveProcessLinks od tej wartości, aby dostać się na początek struktury _EPROCESS dla następnego procesu na liście (3). Następnie, gdy już jesteśmy w następnym procesie, odczytujemy (4) i porównujemy pole UniqueProcessId z bieżącym identyfikatorem procesu (1). Jeśli identyfikator procesu jest zgodny, bieżący proces został znaleziony i możemy przejść do ostatniego kroku exploita. Jeśli bieżący proces nie zostanie znaleziony, program musi przejść do następnego procesu na liście i kontynuować, aż zostanie znaleziony.

W tym momencie pozostało już tylko skopiowanie tokena SYSTEM do pola Token struktury _EPROCESS bieżącego procesu, którą właśnie znaleźliśmy w ostatnim kroku. Aby to zrobić, użyj dowolnej funkcji zapisu wskaźnika, którą napisaliśmy w poprzednim laboratorium. Po nadpisaniu tokena utwórz podproces, taki jak cmd.exe:

Jeśli wszystko pójdzie dobrze, exploit powinien utworzyć powłokę i nie spowodować awarii komputera. Uruchom whoami, jak pokazano poniżej, aby sprawdzić, czy masz SYSTEM!

Możesz napotkać problemy z tym, że program Windows Defender nazwie Twój exploit malware. To malware, więc program Defender po prostu wykonuje swoją pracę! Upewnij się jednak, że po kliknięciu opcji Zezwalaj na urządzeniu wybierasz exploit z listy, a nie rzeczywisty fragment malware.

Arbitralny odczyt/zapis wskaźnika

https://chacker.pl/

Po dokładnym zrozumieniu celu kradzieży tokenów musimy złożyć elementy w całość, aby utworzyć w pełni funkcjonalny exploit eskalacji uprawnień lokalnych. Ponieważ kradzież tokenów obejmuje tylko odczyt i zapis wartości o rozmiarze wskaźnika, możemy uniknąć kłopotów związanych ze wskaźnikami struktury, dodając element usize na końcu struktury DbMemmove:

Teraz możemy napisać jedną funkcję do odczytu wskaźnika w jądrze i inną do zapisu wskaźnika w jądrze. Funkcja odczytu musi przyjąć HANDLE do urządzenia DBUtil i adres do odczytu, a następnie zwrócić zawartość tego adresu:

Ponieważ wyprowadziliśmy Default w definicji struktury, możemy wypełnić jedno pole wymagane do odczytu (1), a następnie zaakceptować wartość domyślną dla pozostałych (0 dla typów całkowitych) (2). Następnie otrzymujemy zmienny surowy wskaźnik do struktury (3), który należy przekazać do funkcji ioctl jako bufor wraz z uchwytem urządzenia, kodem IOCTL dla dowolnego odczytu i rozmiarem struktury (4). Na koniec zwracamy wartość wyjściową (5). Funkcja write musi również przyjąć DBUtil HANDLE, wskaźnik do zapisu, a następnie wartość do zapisu do tego wskaźnika. Ma on bardzo podobny format do poprzedniej funkcji; tym razem wypełnimy element danych struktury i wywołamy funkcję ioctl z dowolnym kodem IOCTL zapisu:

Dzięki tym dwóm funkcjom w naszej bibliotece mamy teraz dwa bardzo wydajne prymitywy i prawie wszystkie składniki, których potrzebujemy, aby podnieść uprawnienia zwykłego użytkownika do SYSTEM.

Kradzież tokenów

https://chacker.pl/

Co możemy zrobić z dowolnym odczytem i zapisem w jądrze? Co najmniej możemy eskalować nasze uprawnienia do SYSTEMU poprzez kradzież tokenów. Proces jest reprezentowany w jądrze systemu Windows za pomocą struktury _EPROCESS (jak w Executive Process). Pierwszym członkiem _EPROCESS jest pole Pcb, które jest zagnieżdżoną strukturą _KPROCESS (jak w Kernel Process). _EPROCESS i _KPROCESS zawierają ogromną ilość informacji o każdym procesie, takich jak identyfikator procesu, nazwa obrazu, token bezpieczeństwa, informacje o sesji, informacje o zadaniu i informacje o wykorzystaniu pamięci. Każdy proces systemu Windows ma powiązany z nim obiekt tokena bezpieczeństwa. Monitor referencyjny bezpieczeństwa jądra używa tokenów do określania dostępnych i aktywnych uprawnień, członkostwa w grupach i innych informacji związanych z uprawnieniami, gdy trzeba podjąć decyzje związane z bezpieczeństwem. Poszczególne wątki również mogą mieć powiązane z nimi tokeny. Struktura _EPROCESS zawiera członka Token, który jest wskaźnikiem zliczanym przez referencje do struktury _TOKEN. To jest podstawowy token procesu. Jeśli nie zostanie nadpisany, proces dziedziczy swój podstawowy token od procesu nadrzędnego. Pomysł kradzieży tokenów polega na nadpisaniu pola Token bieżącego procesu o niższych uprawnieniach wskaźnikiem _TOKEN z procesu o wyższych uprawnieniach. Łatwym i spójnym procesem, z którego można ukraść token o wysokich uprawnieniach, jest proces System. Proces System zawsze ma identyfikator procesu 4 i zawsze ma w pełni uprzywilejowany token z uprawnieniami SYSTEM. Kiedy proces potomny zostanie utworzony pod procesem, którego token został nadpisany skradzionym tokenem SYSTEM, będzie miał uprawnienia SYSTEM. Struktura _EPROCESS zawiera kilka członków, które pomogą nam w tej technice. Pole UniqueProcessId zawiera identyfikator procesu procesu, taki jak można zobaczyć w Menedżerze zadań, więc możemy go użyć do zidentyfikowania procesu systemowego i naszego własnego procesu. Członek ActiveProcessLinks jest podwójnie powiązaną listą, która łączy całą listę procesów. Wskaźniki Flink i Blink nie wskazują na szczyt następnej struktury _EPROCESS, ale raczej na członka ActiveProcessLinks następnej struktury _EPROCESS, jak pokazano poniżej. Oznacza to, że podczas przeglądania listy procesów będziemy musieli odczytać członka ActiveProcessLinks w określonym przesunięciu do _EPROCESS, a następnie odjąć to samo przesunięcie od odczytanej wartości, aby dostać się na szczyt następnego procesu na liście.

Plan zakłada znalezienie wskaźnika do procesu systemowego (PID 4), skopiowanie jego tokena, przejrzenie listy ActiveProcessLinks w celu znalezienia struktury _EPROCESS bieżącego PID, nadpisanie bieżącego tokena procesu tokenem systemowym, a następnie wykonanie podprocesu z podwyższonymi uprawnieniami. Wszystkie pola, z których należy odczytać dane lub do których należy zapisać dane, mają rozmiar wskaźnika, co nieco uprości kod exploita. Aby znaleźć wskaźnik do procesu systemowego, możemy zajrzeć do samego obrazu jądra, który ma wskaźnik do procesu systemowego w symbolu PsInitialSystemProcess. Przesunięcia do każdego pola w _EPROCESS i do symbolu PsInitialSystemProcess zmieniają się między wersjami jądra, więc będziemy musieli uwzględnić to w exploit.