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.

Zapobieganie wykonywaniu danych

https://chacker.pl/

Zapobieganie wykonywaniu danych (DEP) ma na celu zapobieganie wykonywaniu kodu umieszczonego w stercie, stosie i innych sekcjach pamięci, w których wykonywanie kodu nie powinno być dozwolone. Przed rokiem 2004 sprzęt nie obsługiwał tego. W roku 2004 AMD wprowadziło bit NX w swoim procesorze. Po raz pierwszy pozwoliło to sprzętowi rozpoznać stronę pamięci jako wykonywalną lub nie i odpowiednio zareagować. Niedługo potem Intel wprowadził funkcję XD, która robiła to samo. System Windows mógł używać bitu NX/XD od czasu XP SP2 i jest on uważany za dojrzałą i skuteczną kontrolę. Aplikacje można łączyć z flagą /NXCOMPAT, która włączy sprzętowy DEP dla tej aplikacji, w zależności od wersji systemu operacyjnego i obsługi różnych krytycznych funkcji związanych z uprawnieniami i zabezpieczeniami pamięci.

Omijanie SafeSEH

https://chacker.pl/

Jak już wcześniej wspomniano, gdy wyzwolony zostanie wyjątek, system operacyjny umieszcza funkcję except_handler na stosie i wywołuje ją.

Po pierwsze, zauważ, że gdy wyjątek jest obsługiwany, wskaźnik _EstablisherFrame jest przechowywany w ESP+8. Wskaźnik _EstablisherFrame wskazuje w rzeczywistości na szczyt naszego łańcucha obsługi wyjątków. Dlatego jeśli zmienimy wskaźnik _next naszego nadpisanego rekordu wyjątku na instrukcję asemblera EB 06 90 90 (która przeskoczy o 6 bajtów do przodu) i zmienimy wskaźnik _handler gdzieś w udostępnionym pliku DLL/EXE, w sekwencji POP/POP/RETN, możemy przekierować kontrolę programu do naszego obszaru kodu atakującego na stosie. Gdy wyjątek jest obsługiwany przez system operacyjny, zostanie wywołany program obsługi, który rzeczywiście zdejmie 8 bajtów ze stosu i wykona instrukcję wskazywaną na ESP+8 (która jest naszym poleceniem JMP 06), a kontrola zostanie przekierowana do obszaru kodu atakującego na stosie, gdzie może zostać umieszczony kod powłoki.

UWAGA: W tym przypadku musieliśmy przeskoczyć tylko o 6 bajtów do przodu, aby wyczyścić następujący adres i 2 bajty instrukcji skoku. Czasami, ze względu na ograniczenia przestrzeni, może być potrzebny skok wstecz na stosie; w takim przypadku, można użyć liczby ujemnej, aby przeskoczyć wstecz (na przykład EB FA FF FF przeskoczy wstecz o 6 bajtów).

Bezpieczna strukturalna obsługa wyjątków

https://chacker.pl/

Celem ochrony Bezpieczna strukturalna obsługa wyjątków (SafeSEH) jest zapobieganie nadpisywaniu i używaniu struktur SEH przechowywanych na stosie. Jeśli program jest kompilowany i linkowany z opcją linkera /SafeSEH, nagłówek tego pliku binarnego będzie zawierał tabelę wszystkich prawidłowych obsługi wyjątków; tabela ta będzie sprawdzana, gdy zostanie wywołana obsługa wyjątków, aby upewnić się, że znajduje się ona na liście. Sprawdzanie jest wykonywane jako część procedury RtlDispatchException w ntdll.dll, która wykonuje następujące testy:

  • Zapewnia, że ​​rekord wyjątku znajduje się na stosie bieżącego wątku.
  • Zapewnia, że ​​wskaźnik obsługi nie wskazuje z powrotem na stos.
  • Zapewnia, że ​​obsługa jest zarejestrowana na autoryzowanej liście obsługi.
  • Zapewnia, że ​​obsługa znajduje się w obrazie pamięci, który jest wykonywalny.

Jak widać, mechanizm ochrony SafeSEH podejmuje kroki w celu ochrony obsługi wyjątków, ale jak zaraz zobaczysz, nie jest on niezawodny.

Zrozumienie i omijanie typowych zabezpieczeń pamięci systemu Windows

https://chacker.pl/

Jak można było się spodziewać, z czasem atakujący nauczyli się wykorzystywać brak zabezpieczeń pamięci w poprzednich wersjach systemu Windows. W odpowiedzi, mniej więcej w czasie Windows XP SP2 i Server 2003, Microsoft zaczął dodawać zabezpieczenia pamięci, które przez pewien czas były dość skuteczne. Jednak atakujący ostatecznie nauczyli się również obejść te początkowe zabezpieczenia. Jest to ciągła ewolucja technik eksploatacji i zabezpieczeń w celu udaremnienia sukcesu tych technik. Na przestrzeni lat dodano wiele nowych zabezpieczeń, a nawet zestawy narzędzi łagodzących, takie jak Windows Defender Exploit Guard, który zadebiutował w systemie Windows 10 w wersji 1709. Gdy te zabezpieczenia są połączone, mogą one znacznie utrudnić wykorzystanie luki.

Zrozumienie obsługi wyjątków strukturalnych

https://chacker.pl/

Gdy programy ulegają awarii, system operacyjny udostępnia mechanizm o nazwie Obsługa wyjątków strukturalnych (SEH), aby spróbować odzyskać operacje. Jest to często implementowane w kodzie źródłowym za pomocą bloków try/catch lub try/exception:

System Windows śledzi rekordy SEH, korzystając ze specjalnej struktury:

Struktura EXCEPTION_REGISTRATION ma rozmiar 8 bajtów i zawiera dwa elementy:

  • prev Wskaźnik do następnego rekordu SEH
  • handler Wskaźnik do rzeczywistego kodu obsługi

Te rekordy (ramki wyjątku) są przechowywane na stosie w czasie wykonywania i tworzą łańcuch. Początek łańcucha jest zawsze umieszczany w pierwszym elemencie bloku informacji o wątku (TIB), który jest przechowywany na maszynach x86 w rejestrze FS:[0]. Jak pokazano na rysunku , końcem łańcucha jest zawsze domyślny systemowy program obsługi wyjątku, a wskaźnik prev tego rekordu EXCEPTION_REGISTRATION jest zawsze równy 0xFFFFFFFF.

Gdy zostanie wyzwolony wyjątek, system operacyjny (ntdll.dll) umieszcza następującą funkcję C++ na stosie i wywołuje ją:

W przeszłości atakujący mógł po prostu nadpisać jeden z programów obsługi wyjątków na stosie i przekierować kontrolę do kodu atakującego (na stosie).

Jednak później pewne rzeczy uległy zmianie:

  • Rejestry są zerowane tuż przed wywołaniem programów obsługi wyjątków.
  • Wywołania programów obsługi wyjątków, znajdujących się na stosie, są blokowane.

Łańcuch SEH może być interesującym celem, ponieważ często, nawet jeśli nadpisujesz wskaźnik powrotu na stosie, wykonanie nigdy nie osiąga instrukcji powrotu. Jest to zwykle spowodowane naruszeniem dostępu do odczytu lub zapisu, które ma miejsce przed osiągnięciem epilogu funkcji, spowodowane dużą liczbą znaków wysłanych do bufora, które nadpisały krytyczne dane. W takim przypadku dalej w dół stosu za buforem znajduje się lokalizacja łańcucha SEH dla wątku. Naruszenie dostępu do odczytu lub zapisu spowoduje, że FS:[0] zostanie poddane getdereferenced, co zawiera wskaźnik do adresu stosu wątku, gdzie przechowywana jest pierwsza wartość „Next SEH” (NSEH). Rejestr segmentu FS zawsze wskazuje na Thread Information Block (TIB) dla aktualnie aktywnego wątku. TIB to struktura użytkownika na wątek, która przechowuje dane, takie jak wskaźnik do początku łańcucha SEH dla wątku w FS:[0], limity stosu i wskaźnik do Process Environment Block (PEB) w FS:[0x30]. Bezpośrednio pod pozycją NSEH na stosie znajduje się adres pierwszego wywołanego programu obsługi. Nadpisanie tego adresu adresem niestandardowym jest często łatwym sposobem na uzyskanie kontroli, jeśli nie można tego zrobić za pomocą nadpisywania wskaźnika powrotu. SafeSEH ma na celu uniemożliwienie działania tej techniki, ale jak zobaczysz, można ją łatwo ominąć.

Debugowanie Exploitu, jeśli to konieczne

https://chacker.pl/

Czas zresetować system wirtualny i uruchomić poprzedni skrypt. Pamiętaj, aby szybko podłączyć się do wsshd.exe i nacisnąć klawisz F9, aby uruchomić program. Pozwól programowi osiągnąć początkowy wyjątek. Kliknij w dowolnym miejscu sekcji demontażu i naciśnij klawisze CTRL-G, aby wyświetlić okno dialogowe Wprowadź wyrażenie do wykonania. Wprowadź adres z Mona, którego używasz do przejścia do ESP, jak pokazano poniżej. W tym przykładzie było to 0x7c345c30 z MSVCR71.dll. Naciśnij klawisz F9, aby osiągnąć punkt przerwania.

Jeśli program ulega awarii zamiast osiągnąć punkt przerwania, istnieje prawdopodobieństwo, że masz zły znak w kodzie powłoki lub w skrypcie występuje błąd. Problemy ze złymi znakami zdarzają się od czasu do czasu, ponieważ podatny program (lub program klienta SCP w tym przypadku) może reagować na pewne znaki i powodować przerwanie lub inną modyfikację exploita. Aby znaleźć zły znak, musisz przejrzeć zrzut pamięci debugera i dopasować ten zrzut pamięci do rzeczywistego kodu powłoki wysłanego przez sieć. Aby skonfigurować tę inspekcję, musisz powrócić do systemu wirtualnego i ponownie wysłać skrypt ataku. Gdy zostanie osiągnięty początkowy wyjątek, kliknij sekcję stosu i przewiń w dół, aż zobaczysz litery A. Kontynuuj przewijanie w dół, aby znaleźć kod powłoki, a następnie wykonaj ręczne porównanie. Innym prostym sposobem wyszukiwania złych znaków jest wysyłanie wszystkich możliwych kombinacji pojedynczego bajtu sekwencyjnie jako danych wejściowych. Możesz założyć, że 0x00 to zły znak, więc wpisz coś takiego:

UWAGA: Może być konieczne wielokrotne powtórzenie procesu wyszukiwania złych znaków, aż kod zostanie wykonany poprawnie. Generalnie należy wykluczyć wszystkie znaki odstępu: 0x00, 0x20, 0x0a, 0x0d, 0x1b, 0x0b i 0x0c. Należy wykluczać po jednym znaku na raz, aż wszystkie oczekiwane bajty pojawią się w segmencie stosu.

Gdy to będzie działać poprawnie, należy osiągnąć punkt przerwania ustawiony w instrukcjach PUSH ESP i RETN. Naciśnij klawisz F7, aby wykonać pojedynczy krok. Wskaźnik instrukcji powinien teraz wskazywać na wypełnienie NOP. Krótkie sanki lub wypełnienie powinny być widoczne w sekcji deasemblera, jak pokazano tutaj:

Naciśnij F9, aby kontynuować wykonywanie. Na ekranie powinien pojawić się kalkulator, jak pokazano poniżej, pokazując w ten sposób wykonanie kodu powłoki w naszym działającym exploicie! Zademonstrowaliśmy teraz podstawowy proces rozwoju exploita Windows na rzeczywistym exploicie.

Więliśmy podatną na ataki aplikację Windows i napisaliśmy działający exploit, aby naruszyć system docelowy. Celem było zwiększenie Twojej znajomości Immunity Debugger i wtyczki Mona od Corelan Team, a także wypróbowanie podstawowych technik powszechnie stosowanych przez twórców exploitów w celu skutecznego naruszenia bezpieczeństwa aplikacji. Identyfikując moduły, które nie uczestniczyły w różnych kontrolach ograniczających ataki, takich jak ASLR, byliśmy w stanie użyć ich do uzyskania niezawodnego exploita. Następnie przyjrzymy się bliżej różnym zabezpieczeniom pamięci i technikom obejścia.

Budowanie exploita

https://chacker.pl/

Jesteśmy wreszcie gotowi, aby złożyć części razem i zbudować exploit:

UWAGA: Czasami wymagane jest użycie NOP lub padding przed shellcode. Shellcode Metasploit potrzebuje trochę miejsca na stosie, aby zdekodować się podczas wywoływania procedury GETPC, jak opisano przez „sk” w jego artykule Phrack 62:

UWAGA: Czasami wymagane jest użycie NOP lub padding przed shellcode. Shellcode Metasploit potrzebuje trochę miejsca na stosie, aby zdekodować się podczas wywoływania procedury GETPC, jak opisano przez „sk” w jego artykule Phrack 62:

Określanie wektora ataku

https://chacker.pl/

W systemach Windows stos znajduje się w dolnym zakresie adresów pamięci. Stanowi to problem z techniką ataku Aleph 1, której użyliśmy w exploitach Linuksa. W przeciwieństwie do scenariusza programu meet.exe w przypadku exploitów w świecie rzeczywistym nie możemy po prostu kontrolować EIP za pomocą adresu powrotu na stosie. Adres prawdopodobnie będzie zawierał 0x00 na początku i spowoduje problemy, gdy przekażemy ten bajt NULL do podatnego programu. W systemach Windows trzeba będzie znaleźć inny wektor ataku. Często znajdziesz część (jeśli nie całość) swojego bufora w jednym z rejestrów, gdy program Windows ulegnie awarii. Jak pokazano w poprzedniej sekcji, kontrolujemy obszar stosu, w którym program ulega awarii. Wszystko, co musimy zrobić, to umieścić nasz kod powłoki zaczynający się od bajtu 496 i nadpisać wskaźnik powrotu adresem kodu operacji, aby jmp lub wywołać esp. Wybraliśmy ten wektor ataku, ponieważ każdy z tych kodów operacji umieści wartość ESP w EIP i wykona kod pod tym adresem. Inną opcją jest znalezienie sekwencji instrukcji, która wykonuje push esp, a następnie ret. Aby znaleźć adres żądanego kodu operacji, musimy przeszukać załadowane moduły (biblioteki DLL), które są dynamicznie powiązane z programem ProSSHD. Pamiętaj, że w Immunity Debugger możesz wyświetlić listę połączonych modułów, naciskając ALT-E. Użyjemy narzędzia Mona, aby przeszukać załadowane moduły. Najpierw użyjemy Mona, aby ustalić, które moduły nie uczestniczą w kontrolach ograniczających eksploatację, takich jak /REBASE i randomizacja układu przestrzeni adresowej (ASLR). Często zdarza się, że moduły dołączone do aplikacji innej firmy nie uczestniczą w niektórych lub wszystkich tych kontrolach. Aby dowiedzieć się, które moduły chcemy wykorzystać jako część naszego eksploitu, uruchomimy polecenie !mona modules z wnętrza Immunity Debugger. Możesz również użyć !mona modules -o, aby wykluczyć moduły systemu operacyjnego. Wystąpienie wsshd.exe, do którego wcześniej dołączyliśmy za pomocą Immunity Debugger, powinno być nadal aktywne, pokazując poprzedni wzorzec w EIP. Jeśli nadal nie jest aktywne, kontynuuj i ponownie uruchom poprzednie kroki, dołączając do procesu wsshd.exe. Po dołączeniu debugera do procesu uruchom następujące polecenie, aby uzyskać takie same wyniki:

Jak widać z próbki danych wyjściowych Mona, moduł MSVCR71.dll nie jest chroniony przez większość dostępnych kontroli exploitmitigation. Co najważniejsze, nie jest on ponownie bazowany i nie uczestniczy w ASLR. Oznacza to, że jeśli znajdziemy nasz pożądany kod operacji, jego adres powinien być niezawodny w naszym exploicie, omijając ASLR! Będziemy teraz nadal używać wtyczki Mona od Petera Van Eeckhoutte’a (znanego również jako corelanc0d3r) i zespołu Corelan. Tym razem użyjemy jej, aby znaleźć nasz pożądany kod operacji z MSVCR71.DLL. Uruchom następujące polecenie:

Jak widać z próbki danych wyjściowych Mona, moduł MSVCR71.dll nie jest chroniony przez większość dostępnych kontroli exploitmitigation. Co najważniejsze, nie jest on ponownie bazowany i nie uczestniczy w ASLR. Oznacza to, że jeśli znajdziemy nasz pożądany kod operacji, jego adres powinien być niezawodny w naszym exploicie, omijając ASLR! Będziemy teraz nadal używać wtyczki Mona od Petera Van Eeckhoutte’a (znanego również jako corelanc0d3r) i zespołu Corelan. Tym razem użyjemy jej, aby znaleźć nasz pożądany kod operacji z MSVCR71.DLL. Uruchom następujące polecenie:

Jak widać z próbki danych wyjściowych Mona, moduł MSVCR71.dll nie jest chroniony przez większość dostępnych kontroli exploitmitigation. Co najważniejsze, nie jest on ponownie bazowany i nie uczestniczy w ASLR. Oznacza to, że jeśli znajdziemy nasz pożądany kod operacji, jego adres powinien być niezawodny w naszym exploicie, omijając ASLR! Będziemy teraz nadal używać wtyczki Mona od Petera Van Eeckhoutte’a (znanego również jako corelanc0d3r) i zespołu Corelan. Tym razem użyjemy jej, aby znaleźć nasz pożądany kod operacji z MSVCR71.DLL. Uruchom następujące polecenie:

Weź wynik poprzedniego polecenia i dodaj go do skryptu ataku (zauważ, że zmienimy nazwę zmiennej z buf na sc). Wykluczamy bajt „\x00”, ponieważ bajty null są zazwyczaj problematyczne. W module scp.py znajduje się parametr o nazwie sanitize. Domyślnie jego wartość jest ustawiana przez wywołanie funkcji o nazwie _sh_quote, która zwraca nasz ciąg znaków ujętych w pojedyncze cudzysłowy. Jest to prawdopodobnie ochrona w kodzie, aby zapobiec lukom w zabezpieczeniach związanym z wstrzykiwaniem poleceń. Zauważysz w nadchodzącym kodzie, że ustawiliśmy sanitize na wartość równą funkcji lambda, która po prostu zwraca tę samą wartość.