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.