Wybór celu

https://chacker.pl/

Jednym z najbardziej palących i istotnych pytań w badaniach nad lukami w zabezpieczeniach jest „jak wybrać cel?”. Chociaż możemy nie być w stanie odpowiedzieć na to pytanie, warto się nad nim zastanowić, ponieważ odnosi się ono do bieżącego tematu. Jeśli chcesz wejść w eksploatację jądra systemu Windows i sterowników jądra, od czego zacząć? Rozpoczęcie od próby znalezienia luk w samym jądrze lub sterownikach opracowanych przez Microsoft może być nieco trudne lub zniechęcające. Jednym z łatwiejszych i bardziej dostępnych punktów wyjścia są znane podatne sterowniki. Kiedyś Microsoft miał znacznie mniej rygorystyczny proces podpisywania sterownika. Obecnie Microsoft wymaga od programistów sterowników przesyłania ich sterowników do portalu w celu uzyskania podpisu wydania Windows Hardware Quality Labs (WHQL).2 Microsoft wydawał certyfikaty wydawcy oprogramowania (SPC), aby strony trzecie mogły podpisywać własne sterowniki przed publikacją; zaprzestali programu po wycieku kilku certyfikatów, a niektórzy wydawcy podpisywali źle zaprojektowane lub celowo niedostatecznie zabezpieczone sterowniki. Niektóre z tych podpisanych sterowników SPC są nadal szeroko dystrybuowane, jak zobaczysz w tej sekcji.

W sierpniu 2019 r. na konferencji DEFCON 27 badacze z Eclypsium Labs zaprezentowali szereg sterowników z lukami, podkreślając ten konkretny problem. Na ich liście znajdowało się 39 sterowników, które umożliwiają operacje takie jak dowolny wirtualny i fizyczny odczyt i zapis, dowolny odczyt-zapis-wykonanie alokacji pamięci jądra oraz dowolny odczyt i zapis rejestru specyficznego dla modelu (MSR). Funkcje te nie są z natury lukami, ponieważ uprzywilejowane aplikacje, takie jak aktualizatory BIOS-u, muszą ich używać, aby działać prawidłowo, ale tutaj liczy się dostęp wymagany do ich wykorzystania. Te sterowniki są dostępne z trybu użytkownika na dowolnym poziomie uprawnień w systemie. W niektórych przypadkach nawet procesy działające z niską lub niezaufaną integralnością mogą je wywołać. Oznacza to, że każdy z wykonywaniem kodu może potencjalnie podnieść swoje uprawnienia do SYSTEMU lub jądra. Sterowniki utworzone przy użyciu starszego modelu sterowników systemu Windows (WDM) mają domyślnie otwarte uprawnienia dostępu. Listy kontroli dostępu można ustawić za pośrednictwem interfejsu API systemu Windows lub we wpisie rejestru dla sterownika; jednak twórcy tych sterowników nie zrobili ani jednego, ani drugiego, ujawniając w ten sposób uprzywilejowaną funkcjonalność. W maju 2021 r. badacz Sentinel Labs Kasif Dekel opublikował artykuł szczegółowo opisujący szeroko rozpowszechniony sterownik Dell z podobnymi problemami do tych na liście sterowników Eclypsium.4 Jedną z interesujących rzeczy dotyczących tego sterownika jest zakres dystrybucji — prawie 400 platform zostało dotkniętych tym problemem i ujawnieniem. Sterownik nazywa się DBUtil_2_3.sys i jest dołączony do narzędzi aktualizujących Dell i Alienware od 2009 r. Został podpisany przez zewnętrzną firmę Dell SPC i nie został sprawdzony ani przesłany do firmy Microsoft. Ponieważ jest to niedawna luka w zabezpieczeniach i ma tak duży zakres, jest idealnym celem do nauki wykorzystywania jądra.

Konfigurowanie debugowania jądra

https://chacker.pl/

Aby rozpocząć, będziesz potrzebować dwóch maszyn wirtualnych z systemem Windows 10 i wybranego oprogramowania do wirtualizacji (VMware, VirtualBox, Parallels itd.). Możesz również użyć systemu Windows 11, jeśli masz jego kopię, ponieważ proces i wyniki powinny być takie same. Jeśli masz licencję systemu Windows i maszyny wirtualne są już skonfigurowane, to świetnie! Jeśli w ogóle nie masz maszyn wirtualnych z systemem Windows 10, masz kilka opcji: pobierz obraz ISO systemu Windows 10 od firmy Microsoft i użyj wersji próbnej systemu Windows lub przejdź do zasobów dla programistów systemu Windows i pobierz starszą wersję VM dla programistów programu Internet Explorer. Sprawdź sekcję „Dalsze informacje”, aby uzyskać łącza. Ta ostatnia jest nadal dostarczana przez firmę Microsoft w momencie pisania, chociaż może to ulec zmianie!

UWAGA: Te testowe maszyny wirtualne są dopuszczalne do użytku laboratoryjnego, ale jeśli zamierzasz używać systemu Windows jako swojego systemu operacyjnego lub komercyjnie, musisz kupić licencję. Kradzież jest zła!

Gdy masz jedną maszynę wirtualną Windows 10 skonfigurowaną według własnych upodobań, utwórz pełny lub połączony klon. Jedna maszyna wirtualna będzie maszyną debugera, na której zainstalujesz WinDbg, a druga będzie celem debugowania. WinDbg Preview można zainstalować ze sklepu Microsoft Store, a WinDbg Classic można zainstalować z zestawu Windows SDK. Aby zainstalować WinDbg Classic, pobierz zestaw Windows SDK i wybierz Narzędzia debugowania dla systemu Windows w instalatorze. Po zakończeniu wszelkich niezbędnych instalacji włącz debugowanie jądra sieciowego, używając bcdedit z powłoki administratora na docelowej maszynie wirtualnej:

Hostip można ustawić na dowolną wartość, jeśli łączysz się przez WinDbg Preview lub określ zmienną docelową w ciągu połączenia WinDbg Classic; w przeciwnym razie ustaw ją na adres IP maszyny wirtualnej debugera. Skopiuj zwrócony klucz na maszynę debugera, ponieważ będzie on potrzebny do połączenia zdalnego. Uruchom ponownie maszynę wirtualną docelową, aby uruchomić tryb debugowania. Połącz się z WinDbg Preview, przechodząc do Plik | Dołącz do jądra, a następnie wprowadzając wymagane informacje na karcie Sieć. W przypadku WinDbg Classic lub kd.exe użyj flagi -k w wierszu poleceń i wprowadź ten ciąg połączenia, zastępując wartości w nawiasach kątowych wartościami specyficznymi dla Twojego środowiska:

Jeśli połączenie zostanie nawiązane pomyślnie, powinieneś otrzymać aktywny monit w punkcie przerwania (int 3) znajdującym się pod adresem jądra (zaczynającym się od 0xfffff). Wiersz poleceń również będzie aktywny. Jeśli nie możesz się połączyć, sprawdź adres IP celu, upewnij się, że obie maszyny wirtualne mogą połączyć się przez sieć i spróbuj wyłączyć zaporę systemu Windows na obu komputerach. Po nawiązaniu połączenia możesz poeksperymentować z kilkoma poleceniami. WinDbg jest na początku bardzo przytłaczający, ale nie martw się, z czasem staje się łatwiejszy. Po skonfigurowaniu debugowania jądra jesteś teraz gotowy, aby przejść do identyfikacji celu hakowania jądra!

Debugowanie jądra

https://chacker.pl/

Debuger w przestrzeni użytkownika (pierścień 3) jest w stanie debugować tylko poszczególne programy, które działają na jądrze. Debuger w przestrzeni jądra (pierścień 0) jest wymagany do debugowania jądra. Debugowanie jądra jest zwykle wykonywane między dwoma systemami: jeden uruchamia debuger, a drugi jest systemem, który jest debugowany. Potrzebne są dwa systemy, ponieważ w przeciwieństwie do zawieszenia pojedynczego programu w debugerze pierścienia 3, zatrzymanie całego jądra uniemożliwiłoby interakcję z systemem w celu uruchomienia poleceń lub wznowienia go! Istnieje jeden wyjątek znany jako „lokalne” debugowanie jądra, który umożliwia wygodne debugowanie jądra aktualnie uruchomionego systemu. Główną wadą lokalnego debugowania jądra jest to, że nie można zatrzymać uruchomionego systemu, co oznacza, że ​​nie można ustawić ani wstrzykiwać żadnych punktów przerwania ani debugować w przypadku awarii, a ponieważ system jest stale uruchomiony, wartości w pamięci mogą się szybko zmieniać. Jedynym oficjalnie obsługiwanym (a zatem zalecanym) debugerem pierścienia 0 dla systemu Windows jest WinDbg, który zwykle wymawia się jako win-dee-bee-gee, wind-bag lub win-dee-bug. Jest on rozwijany i utrzymywany przez firmę Microsoft i dołączany jako część pakietów narzędzi programistycznych. WinDbg oferuje szereg różnych transportów, w których można debugować jądro. Debugowanie sieciowe jest najbardziej niezawodną, ​​wydajną i spójną konfiguracją debugowania jądra. WinDbg można uzyskać, instalując zestaw Windows SDK, WDK lub ze sklepu Microsoft Store jako WinDbg Preview. Nowszy WinDbg Preview to ten sam WinDbg, ale z interfejsem podobnym do metro. Laboratoria w tej sekcji będą używać WinDbg Preview. Jeśli jesteś bardziej fanem wiersza poleceń, możesz użyć kd.exe, aby połączyć się z systemem docelowym. Jest on dołączony obok WinDbg w zestawie SDK i WDK. Wszystkie odmiany WinDbg są wspierane przez DbgEng, który stanowi podstawową funkcjonalność WinDbg. Microsoft dołącza pliki nagłówkowe i biblioteki do interakcji z DbgEng w Windows SDK, aby programiści mogli pisać narzędzia, które wykorzystują bibliotekę, która wspiera programowo WinDbg.

Sterowniki jądra

https://chacker.pl/

Sterowniki jądra to rozszerzenia jądra, które mogą pomóc systemowi w interakcji z wcześniej nieznanymi urządzeniami lub systemami plików, zapewnić interfejs do introspekcji jądra do trybu użytkownika i zmodyfikować sposób działania jądra. To ostatnie jest mocno zniechęcane przez Microsoft, tak bardzo, że firma wprowadziła Kernel Patch Protection (znany również jako PatchGuard), aby uniemożliwić programistom ingerencję w podstawowe procedury systemowe i struktury danych. Sterowniki jądra znane jako sterowniki rozruchowe są ładowane podczas rozruchu przez program ładujący. Inne sterowniki są ładowane przez menedżera usług po uruchomieniu systemu. Tylko administratorzy lub osoby z uprawnieniami SeLoadDriverPrivilege mogą ładować sterowniki w systemie Windows. Microsoft nie uważa granicy między administratorem systemu a jądrem za granicę bezpieczeństwa, ponieważ administratorzy mogą po prostu ładować (prawie) dowolne sterowniki. Jednak sterowniki muszą mieć akceptowalny podpis cyfrowy, aby mogły zostać załadowane, ponieważ podpisywanie kodu w trybie jądra (KMCS) jest wymuszane domyślnie na wszystkich maszynach 64-bitowych. Sterownik może udostępniać procedury wejścia/wyjścia (I/O) w formie głównych funkcji. Windows Driver Kit (WDK) definiuje 28 głównych funkcji, w tym tworzenie, zamykanie, zasilanie, sterowanie we/wy, odczyt, zapis, wyszukiwanie informacji, ustawianie informacji i wyłączanie. Obsługujące funkcje dla każdej głównej funkcji są ustawiane wewnątrz struktury _DRIVER_OBJECT sterownika, gdy sterownik jest inicjowany. Ta struktura zawiera różne informacje o sterowniku, takie jak nazwa sterownika, połączona lista urządzeń skojarzonych ze sterownikiem, opcjonalna procedura rozładowania, która jest wywoływana, gdy żądane jest rozładowanie sterownika, oraz ograniczenia pamięci sterownika (start i rozmiar). Sterownik może tworzyć powiązane struktury _DEVICE_OBJECT, które reprezentują urządzenie, za które odpowiada sterownik. Urządzenia mogą być lub nie być obsługiwane przez rzeczywisty sprzęt. Przykładem sterownika nieobsługiwanego sprzętowo jest sterownik, którego Sysinternal Process Explorer używa do uzyskania dodatkowych informacji o systemie. W przypadku Process Explorera sterownik podpisany przez Microsoft jest ładowany podczas uruchamiania narzędzia, a do komunikacji z nim używane są interfejsy API trybu użytkownika. Sterownik tworzy obiekt urządzenia dostępny w trybie użytkownika i obsługuje żądania z trybu użytkownika za pośrednictwem systemu I/O w jądrze. System I/O jądra wysyła żądania do głównej procedury obsługi funkcji zdefiniowanej w _DRIVER_OBJECT, do którego należy urządzenie. Główne kody funkcji to stałe wartości całkowite zdefiniowane w nagłówkach WDK. Wszystkie ich nazwy symboli zaczynają się od IRP_MJ_ i są indeksami w głównej tablicy funkcji _DRIVER_OBJECT, zaczynając od 0x70. Główne procedury obsługi funkcji są również nazywane procedurami obsługi sterowników i mają następujący prototyp:

Pakiet żądania wejścia/wyjścia (IRP) opisuje żądanie wejścia/wyjścia do urządzenia. Zawiera wiele pól, które staną się ważne, gdy będziesz pracować nad laboratorium w dalszej części rozdziału. Kilka godnych uwagi pól obejmuje pole AssociatedIrp.SystemBuffer, które często obejmuje bufor wejściowy i/lub wyjściowy dla żądania, oraz pole Tail.Overlay.CurrentStackLocation, które zawiera informacje o żądaniu odnoszące się do konkretnego wywoływanego urządzenia. Ważne informacje w CurrentStackLocation (_IO_STACK_LOCATION) obejmują pole MajorFunction, które jest bieżącą żądaną funkcją główną, oraz pole Parameters, które jest masywną unią zawierającą różne informacje w zależności od wywoływanej funkcji głównej. W przypadku sterowania wejściem/wyjściem urządzenia, pole MajorFunction będzie miało wartość IRP_MJ_DEVICE_CONTROL (14), a pole Parameters będzie opisywać wywoływany kod sterowania wejściem/wyjściem (IOCTL) oraz rozmiary buforów wejściowych i wyjściowych. W przypadku większości wywołań IOCTL bufor wejściowy i/lub wyjściowy będzie znajdował się w polu AssociatedIrp.SystemBuffer w _IRP. Aby uzyskać więcej informacji na temat kodów IOCTL, zapoznaj się z dokumentacją systemu Windows. W laboratoriach w tym rozdziale wykonasz inżynierię wsteczną i debuggowanie sterownika jądra, aby zlokalizować urządzenie, które tworzy, określisz główne programy obsługi funkcji, które są zarejestrowane, nauczysz się wywoływać główne programy obsługi funkcji z trybu ser i ostatecznie napiszesz exploit, aby wykonać lokalną eskalację uprawnień (LPE).

Jądro systemu Windows

https://chacker.pl

Ponieważ jądro systemu Windows jest tak złożone, będziemy mogli omówić tylko podstawy jądra i pewne informacje, które będą potrzebne do zrozumienia exploita w dalszej części rozdziału. Istnieje wiele bardziej kompleksowych zasobów dotyczących jądra systemu Windows i wewnętrznych mechanizmów jądra, w tym Windows Internals, 7th Edition (Parts 1 and 2), Windows Kernel Programming autorstwa Pavla Yosifovicha oraz różne posty na blogach rozsiane po Internecie. Cennymi materiałami źródłowymi są również Windows Software Development Kit (SDK), Windows Driver Kit (WDK) oraz podręczniki procesorów Intel/AMD/ARM. Ponadto będziemy przeglądać koncepcje i wykorzystywać 64-bitowy system Windows (32-bitowy system Windows jest w niektórych przypadkach nieco inny, ale z czasem staje się coraz mniej istotny). Jądro jest implementowane jako warstwa jądra, warstwa wykonawcza i sterowniki. Warstwy jądra i wykonawcze są implementowane w obrazie jądra, ntoskrnl.exe. Warstwa jądra zawiera kod do planowania wątków, blokowania, synchronizacji i podstawowego zarządzania obiektami jądra. Warstwa wykonawcza zawiera kod do egzekwowania zabezpieczeń, zarządzania obiektami, zarządzania pamięcią, rejestrowania i instrumentacji zarządzania systemem Windows, między innymi. Większość sterowników jądra to pliki .sys, ale kilka komponentów jądra to biblioteki DLL, takie jak hal.dll i ci.dll. Plik .sys to przenośny plik wykonywalny, podobnie jak plik EXE lub DLL. Poniższy diagram systemu pokazuje ogólny układ architektury systemu Windows.

Zaczynając od dołu, istnieją aplikacje i usługi w trybie użytkownika, które są uruchamiane na podsystemie Windows (kernel32.dll, user32.dll itd.), są tworzone bezpośrednio dla natywnego API (ntdll.dll i win32u.dll) lub są uruchamiane jako procesy minimalne/pico i komunikują się bezpośrednio z jądrem za pośrednictwem System Service Dispatcher. System Service Dispatcher (znany również jako system call handler) pobiera żądania z trybu użytkownika i wysyła je do jądra. Przechodząc przez linię, powinieneś zauważyć, że adresy idą od niższych w trybie użytkownika do znacznie wyższych w trybie jądra. Pamięć jest segmentowana w ten sposób z powodów historycznych i specyficznych dla procesora. Tak się składa, że ​​istnieją dwie odrębne kanoniczne przestrzenie pamięci z dużą niekanoniczną luką pośrodku, aby podzielić pamięć należącą do przestrzeni jądra (pierścień 0) i przestrzeni użytkownika (pierścień 3). Po stronie trybu jądra znajduje się warstwa jądra, warstwa wykonawcza i sterowniki, jak wspomniano wcześniej. Niektóre sterowniki, takie jak sterowniki graficzne, mogą komunikować się bezpośrednio ze sprzętem, podczas gdy inne będą używać warstwy abstrakcji sprzętowej (HAL). HAL to niezależna od architektury i platformy biblioteka do interakcji ze sprzętem. W ostatnich wersjach systemu Windows 10 (20H1+) HAL jest implementowany wewnątrz obrazu jądra, a hal.dll to po prostu przekazująca biblioteka DLL, która nadal istnieje ze względu na kompatybilność. Nie martw się, jeśli jest to dużo do przyswojenia, ponieważ jest to tylko przegląd komponentów systemu Windows.

Wykorzystanie jądra systemu Windows

https://chacker.pl/

Jądro systemu Windows i pisanie exploitów jądra to ogromne tematy; nauka wewnętrznych mechanizmów jądra i właściwego stosowania tej wiedzy w celu wykorzystania luk w zabezpieczeniach zajmuje lata. Luki te można znaleźć nie tylko w samym jądrze, ale także w rozszerzeniach znanych jako sterowniki. Tu przyjrzymy się, jak skonfigurować debugowanie jądra między dwoma systemami Windows, przeprowadzić inżynierię wsteczną sterownika jądra, a następnie wykorzystać ten sterownik jądra w celu podniesienia naszych uprawnień.

 

Podsumowanie

https://chacker.pl/

Techniki pokazane tu powinny pomóc Ci w opanowaniu podstaw eksploatacji systemu Windows za pomocą przepełnień stosu, a także omijania prostych środków zapobiegawczych, takich jak SafeSEH i DEP. Jak już widziałeś, w systemach operacyjnych Microsoft istnieją różne zabezpieczenia, w zależności od wybranych opcji kompilatora i innych czynników. Każda ochrona wiąże się z nowymi wyzwaniami dla atakujących, co skutkuje grą w kotka i myszkę. Zabezpieczenia, takie jak te oferowane przez Exploit Guard, mogą pomóc zatrzymać gotowe exploity, ale jak już wspomniano, doświadczony atakujący może dostosować exploit, aby ominąć wiele z tych kontroli.

Budowanie łańcucha ROP

https://chacker.pl/

Korzystając z wtyczki Mona PyCommand z corelanc0d3r, możemy znaleźć listę zalecanych gadżetów dla danego modułu (-cp nonull jest używane, aby upewnić się, że żadne bajty zerowe nie są używane jako część łańcuchów ROP):

Wykonanie tego polecenia powoduje utworzenie kilku plików, w tym następujących:

  • Plik rop_chains.txt zawierający ukończone lub częściowo ukończone łańcuchy ROP, których można użyć do obejścia DEP, używając funkcji takich jak VirtualProtect() i VirtualAlloc(). Te łańcuchy mogą zaoszczędzić Ci niezliczonych godzin ręcznego przeglądania i budowania łańcucha ROP.
  • Plik rop.txt zawierający dużą liczbę gadżetów, które mogą być przydatne jako część Twojego exploita. Często zdarza się, że wygenerowane łańcuchy ROP działają od razu po wyjęciu z pudełka. Często będziesz szukać gadżetów, aby zrekompensować ograniczenia, a plik rop.txt może Ci w tym pomóc.
  • Plik o nazwie stackpivot.txt, który będzie zawierał tylko instrukcje stack pivot.
  • W zależności od używanej wersji Mona, mogą zostać wygenerowane inne pliki, takie jak rop_suggestions.txt i pliki XML zawierające ukończone łańcuchy ROP. Ponadto wygenerowane łańcuchy ROP mogą się różnić w zależności od używanej wersji Mona i wybranych opcji. Więcej informacji o funkcji i jej parametrach można znaleźć na stronie Mona usage. Polecenie rop będzie działać przez chwilę i wygeneruje pliki wyjściowe do dowolnego folderu wybranego w Mona za pomocą polecenia !mona config -set workingfolder <PATH>/%p. Zawartość bardzo szczegółowego pliku rop.txt będzie zawierać wpisy takie jak ten:

Na podstawie tego wyniku możesz połączyć ze sobą gadżety, aby wykonać zadanie, budując argumenty dla VirtualProtect() i wywołując je. Nie jest to takie proste, jak się wydaje; musisz pracować z tym, co masz do dyspozycji. Być może będziesz musiał wykazać się kreatywnością. Poniższy kod, uruchomiony względem programu ProSSHD, demonstruje działający łańcuch ROP, który wywołuje VirtualProtect() w celu zmodyfikowania uprawnień, w których znajduje się kod powłoki na stosie, tak aby stał się wykonywalny. DEP został ponownie włączony dla wsshd.exe. Skrypt został nazwany prosshd_dep.py.

Chociaż na początku przestrzeganie tego programu może wydawać się trudne, gdy uświadomisz sobie, że jest to po prostu seria wskaźników do obszarów połączonych modułów, które zawierają cenne instrukcje, po których następuje instrukcja RETN, która po prostu zwraca następny gadżet, wtedy możesz zobaczyć metodę szaleństwa. Istnieje kilka gadżetów do ładowania wartości rejestrów (przygotowując się do wywołania VirtualProtect). Istnieją inne gadżety do kompensowania różnych problemów, aby zapewnić, że prawidłowe argumenty są ładowane do odpowiednich rejestrów. Podczas korzystania z łańcucha ROP wygenerowanego przez Mona, ten autor ustalił, że po prawidłowym wyrównaniu wywołanie VirtualProtect() jest pomyślnie wykonywane; jednak po powrocie z SYSEXIT z Ring0, wracamy zbyt daleko w dół stosu i do środka naszego kodu powłoki. Aby to zrekompensować, ręcznie dodano kilka gadżetów, aby upewnić się, że EBP wskazuje na nasz NOP sled. Można by poświęcić czas na precyzyjne wyrównanie rzeczy, aby tak duże wypełnienie nie było konieczne; jednak ten czas można również poświęcić na inne zadania. Wygenerowany łańcuch ROP może wyglądać zupełnie inaczej niż ten pokazany w tym przykładzie.

W poniższym kodzie najpierw umieszczamy wartość 0xfffffcdf w EAX. Gdy zostanie ona dodana do adresu w EBP, który wskazuje na nasz kod powłoki, zostanie ona przeniesiona o 2^32 i będzie wskazywała na nasz sled NOP.

Aby to obliczyć, wystarczy wykonać podstawowe obliczenia matematyczne, aby upewnić się, że EBP wskazuje na lokalizację wewnątrz sanek NOP. Ostatnia instrukcja wykonuje to dodawanie. Aby zademonstrować stan przed i po, spójrz na poniższe obrazy.

Na tym pierwszym obrazku program jest wstrzymany przed dostosowaniem do EBP. Jak widać, EBP wskazuje na środek shellcode. Następny obraz pokazuje adres, na który wskazuje EBP po dokonaniu dostosowania.

Jak widać, EBP wskazuje na nasz NOP sled, tuż przed shellcode. Shellcode używany w exploicie, wygenerowany za pomocą Metasploit, wiąże shell z portem TCP 31337. Gdy exploitowi pozwolono kontynuować, shellcode jest pomyślnie wykonywany, a port jest otwarty, jak pokazano tutaj z monitem zapory.

Gadżety

https://chacker.pl/

Małe sekcje kodu wymienione w poprzedniej sekcji to to, co nazywamy gadżetami. Słowo kod jest tutaj używane, ponieważ nie musi to być instrukcja używana przez program lub moduł; możesz przejść do adresu w środku zamierzonej instrukcji lub gdziekolwiek indziej w pamięci wykonywalnej, pod warunkiem, że wykonuje ona zadanie, które chcesz wykonać i zwraca wykonanie do następnego gadżetu wskazywanego przez wskaźnik stosu. Poniższy przykład pokazuje zamierzoną instrukcję użytą wewnątrz ntdll.dll pod adresem pamięci 0x778773E2:

Zobacz co się stanie, gdy przejdziemy z 0x778773E2 do 0x778773E3:

Sekwencja kodu nadal kończy się return, ale instrukcja nad return została zmieniona. Jeśli ten kod jest dla nas zrozumiały, możemy go użyć jako gadżetu. Ponieważ następny adres wskazywany przez ESP lub RSP na stosie jest innym gadżetem ROP, polecenie return wywołuje tę następną sekwencję kodu. Ponownie, ta metoda programowania jest podobna do ret2libc i jest w rzeczywistości jej następcą, jak omówiono w rozdziale 10. W ret2libc nadpisujemy wskaźnik return adresem początku funkcji, takiej jak system(). W ROP, gdy tylko uzyskamy kontrolę nad wskaźnikiem instrukcji, wskazujemy mu lokalizację wskaźników do naszych gadżetów i wracamy przez łańcuch. Niektóre gadżety zawierają niechciane instrukcje, które musimy zrekompensować, takie jak POP lub inna instrukcja, która mogłaby negatywnie zmodyfikować stos lub rejestr. Spójrz na deasemblację:

Sekwencja kodu nadal kończy się return, ale instrukcja nad return została zmieniona. Jeśli ten kod jest dla nas zrozumiały, możemy go użyć jako gadżetu. Ponieważ następny adres wskazywany przez ESP lub RSP na stosie jest innym gadżetem ROP, polecenie return wywołuje tę następną sekwencję kodu. Ponownie, ta metoda programowania jest podobna do ret2libc i jest w rzeczywistości jej następcą, jak omówiono w rozdziale 10. W ret2libc nadpisujemy wskaźnik return adresem początku funkcji, takiej jak system(). W ROP, gdy tylko uzyskamy kontrolę nad wskaźnikiem instrukcji, wskazujemy mu lokalizację wskaźników do naszych gadżetów i wracamy przez łańcuch. Niektóre gadżety zawierają niechciane instrukcje, które musimy zrekompensować, takie jak POP lub inna instrukcja, która mogłaby negatywnie zmodyfikować stos lub rejestr. Spójrz na deasemblację:

W tym przykładzie po prostu zmieniliśmy POP EDI na POP EAX. Jeśli naszym celem jest wyzerowanie rejestru EAX, niechciany POP EAX sprawi, że ten gadżet stanie się bezużyteczny. Istnieją inne typy niechcianych instrukcji, z których niektóre mogą być dość trudne do rozwiązania, takie jak dostęp do adresu pamięci, który nie jest mapowany.

 

Programowanie zorientowane na zwrot

https://chacker.pl/

Co więc możemy zrobić, jeśli nie możemy wykonać kodu na stosie? Wykonać go gdzie indziej? Ale gdzie? W istniejących powiązanych modułach jest wiele małych sekwencji kodu, które kończą się instrukcją RETN. Te sekwencje kodu mogą lub nie być wykonywane przez program. Wyobraźmy sobie, że mamy kontrolę nad procesem za pośrednictwem przepełnienia bufora. Jeśli ułożymy serię wskaźników do tych pożądanych sekwencji kodu, na które wskazuje wskaźnik stosu, i wrócimy do każdego z nich po kolei, możemy zachować kontrolę nad procesem i sprawić, by wykonywał nasze polecenia. Nazywa się to programowaniem zorientowanym na zwrot i zostało zapoczątkowane przez Hovava Shachama. Jest to następca technik takich jak ret2libc. Możemy użyć tych gadżetów, aby skonfigurować wywołanie funkcji w celu zmiany uprawnień w pamięci, w której znajduje się nasz kod powłoki, co pozwala nam obejść DEP.