Budowanie exploita

https://chacker.pl/

Doświadczony badacz może łatwo napisać własny shellcode exploita od podstaw; my jednak po prostu skorzystamy z pakietu shellcraft Pwntools. Jednym z wielu przydatnych shellcode’ów, które zawiera, jest funkcja findpeersh. Znajdzie ona deskryptor pliku naszego bieżącego połączenia gniazda i uruchomi na nim wywołanie systemowe dup2, aby przekierować standardowe wejście i wyjście przed uruchomieniem powłoki:

Uruchommy ponownie gdb i uruchommy nasz exploit; powinniśmy odzyskać naszą powłokę:

Zadziałało! Po uruchomieniu exploita odzyskaliśmy powłokę na naszym własnym połączeniu. Teraz możemy wykonywać polecenia w naszej interaktywnej powłoce.

Określanie wektora ataku

https://chacker.pl/

Gdy już wiemy, gdzie EIP jest nadpisywane, musimy określić, na jaki adres na stosie musimy wskazać, aby wykonać ładunek. Aby to zrobić, modyfikujemy nasz kod, aby dodać sanki NOP. Daje nam to większy obszar do skoku, tak że jeśli wydarzy się coś drobnego i nasza lokalizacja trochę się zmieni, nadal wylądujemy gdzieś w naszych instrukcjach NOP. Dodając 32 NOP, powinniśmy nadpisać ESP i mieć dodatkową elastyczność dla adresów, do których można przeskoczyć. Pamiętaj, że żaden adres zawierający „\x00” nie zadziała, ponieważ jest to traktowane jako zakończenie ciągu.

Po ponownym uruchomieniu gdb i uruchomieniu nowego kodu exploita powinniśmy zobaczyć, że EIP jest nadpisany przez 0x42424242 (BBBB). Dzięki nowym zmianom powinniśmy móc sprawdzić nasz stos, aby zobaczyć, gdzie znajduje się NOP sled:

Widzimy, że EIP został nadpisany w (1). W (2) wartości są wypełnione naszymi instrukcjami NOP. Jeśli wskoczymy do środka naszego NOP sled w 0xffffd418 (3), powinno to nas doprowadzić bezpośrednio do naszego shellcode.

Określanie offsetu(ów)

https://chacker.pl/

Mając kontrolę nad rejestrem EIP, musimy dowiedzieć się dokładnie, ile znaków zajęło czyste nadpisanie go (i nic więcej). Najłatwiejszym sposobem na zrobienie tego jest użycie generatora wzorców cyklicznych Pwntools. Najpierw utwórzmy skrypt Pythona, aby połączyć się z naszym nasłuchem:

Gdy ponownie uruchomimy nasz plik binarny w gdb i uruchomimy skrypt Pythona w innym oknie, nadal powinniśmy doświadczyć awarii. Jeśli tak się stanie, skrypt Pythona działa prawidłowo, a błąd segmentacji powinien zostać spowodowany ustawieniem EIP na nieprawidłowy adres pamięci 0x41414141 (AAAA). Następnie chcemy dokładnie ustalić, ile znaków potrzeba, aby przepełnić bufor. Zamiast osiągać to za pomocą odczytywania kodu dezasemblacji, możemy przepełnić program cyklicznym wzorcem: unikalną sekwencją bajtów w ciągu o wstępnie zdefiniowanej długości. Wynikowa wartość nadpisanego EIP będzie odpowiadać czterem unikalnym bajtom w cyklicznym wzorcu, które można łatwo zlokalizować, zapewniając dokładną długość, o jaką powinniśmy uzupełnić nasz kod powłoki, aby osiągnąć przesunięcie zapisanego adresu powrotu w stosie. Użyjemy cyklicznej funkcji Pwntools, aby osiągnąć to w naszym exploicie:

Teraz, gdy uruchamiamy exploit, otrzymujemy inne nadpisanie w gdb:

Tutaj widzimy, że EIP został ustawiony na 0x63616171, co odpowiada sekwencji „caaq” z naszego wzorca cyklicznego. Jeśli zastosujesz się do instrukcji instalacji Pwntools  i wykonasz polecenie sudo pip3 install pwntools, zainstalujesz narzędzia wiersza poleceń Pwntools. Możemy użyć cyklicznego narzędzia wiersza poleceń Pwntools, aby znaleźć przesunięcie odpowiadające 0x63616171:

Jeśli nie chcesz instalować narzędzi wiersza poleceń Pwntools, alternatywą jest uruchomienie konsoli Python3, zaimportowanie Pwntools i użycie funkcji cyclic_find:

Teraz wiemy, że dokładne przesunięcie wynosi 264 bajty, zanim EIP zostanie nadpisane. Daje nam to początkową długość wypełnienia, której potrzebujemy przed wysłaniem lokalizacji nadpisywania EIP.

Tworzenie niestandardowych exploitów

https://chacker.pl/

Tworzenie niestandardowych exploitów.

Sterowanie EIP

Program  jest aplikacją sieciową. Gdy go uruchomimy, będzie nasłuchiwał na porcie 5555:

Podczas testowania aplikacji możemy czasami znaleźć słabości po prostu wysyłając długie ciągi znaków. W innym oknie połączmy się z działającym plikiem binarnym za pomocą netcat:

Teraz użyjmy Pythona, aby utworzyć bardzo długi ciąg i wysłać go jako nazwę użytkownika za pomocą naszego połączenia netcat:

Nasz plik binarny zachowuje się inaczej z długim ciągiem znaków. Aby dowiedzieć się dlaczego, musimy dołączyć gdb. Uruchomimy nasz podatny program w jednym oknie, używając gdb, i wyślemy nasz długi ciąg znaków w innym oknie. Ten program rozwidli proces potomny za każdym razem, gdy zostanie zaakceptowane nowe połączenie. Musisz poinstruować gdb, aby podążał za rozwidlonym procesem potomnym po połączeniu, aby debugować exploit. Możesz to zrobić, uruchamiając set follow-fork-mode child w interfejsie gdb. Rysunek 10-2 pokazuje, co dzieje się na ekranie debugera, gdy wysyłamy długi ciąg znaków. Używając debugera w jednym oknie i naszego długiego ciągu znaków w innym, możemy zobaczyć, że nadpisaliśmy zapisaną ramkę i adres powrotu w pamięci stosu, co skutkuje kontrolą rejestrów EIP i EBP po powrocie z podatnej funkcji

Teraz mamy klasyczne przepełnienie bufora i nadpisaliśmy EIP. To kończy pierwszy krok procesu rozwoju exploita. Przejdźmy do następnego kroku.

Proces rozwoju exploita

https://chacker.pl/

Teraz, gdy omówiliśmy podstawy, jesteś gotowy, aby przyjrzeć się rzeczywistemu przykładowi. W rzeczywistym świecie luki nie zawsze są tak proste, jak przykład meet.c. Proces rozwoju exploita przepełnienia stosu zazwyczaj przebiega według następujących kroków:

  1. Kontroluj przepływ wykonywania (rejestr EIP) poprzez identyfikację luki, która powoduje przepełnienie adresu powrotnego.
  2. Określ przesunięcie(a) i ograniczenia (złe znaki przerywające exploit, takie jak znaki nowego wiersza, powrotu karetki i bajty zerowe).
  3. Określ wektor ataku.
  4. Debuguj i śledź przepływ programu podczas przepełnienia.
  5. Zbuduj exploit.
  6. Przetestuj exploit.

Każda luka będzie miała własne ograniczenia i specjalne sytuacje w zależności od charakteru podatnego programu, flag czasu kompilacji, zachowania i przyczyny głównej podatnej funkcji oraz sposobu, w jaki przekształca ona dane wejściowe powodujące exploit.

Wykorzystywanie małych buforów

https://chacker.pl/

Co się stanie, jeśli podatny bufor będzie zbyt mały, aby użyć bufora exploita, jak opisano wcześniej? Co jeśli znaleziony podatny bufor ma długość tylko 10 bajtów? Przyjrzyjmy się następującemu podatnemu kodowi:

Skompiluj i ustaw bit SUID:

Teraz, gdy mamy taki program, jak moglibyśmy go wykorzystać? Odpowiedź leży w użyciu zmiennych środowiskowych. Możesz przechowywać swój kod powłoki w zmiennej środowiskowej, a następnie wskazać EIP na tę zmienną środowiskową. Zacznijmy od ustawienia zmiennej środowiskowej o nazwie SHELLCODE:

Następnie musimy uzyskać adres wskazujący na tę zmienną środowiskową. Możemy użyć polecenia gdb x/20s *((char **)environ), ale przesunięcia będą inne w tym środowisku. Inną opcją jest wywołanie libc.getenv z Pythona przy użyciu ctypes, ale niestety Python 64-bitowy nie może załadować bibliotek 32-bitowych. Naszą najszybszą opcją jest napisanie małego programu C, który wywoła getenv(“SHELLCODE”):

Skompiluj i uruchom getenv.c:

Zanim napiszemy nasz exploit, otwórzmy smallbuf za pomocą gdb i sprawdźmy, ile bajtów musimy zapisać, aby nadpisać EIP:

Teraz, gdy wiemy, że potrzebujemy 18 bajtów, aby nadpisać EIP, zakończmy i uruchommy nasz exploit:

Wykorzystywanie Stack Overflow z wiersza poleceń

https://chacker.pl/

Pamiętaj, że w laboratorium 10-1 rozmiar potrzebny do nadpisania EIP w meet.c wynosi 412. Dlatego użyjemy Pythona do stworzenia naszego exploita. Najpierw wyłączmy ASLR dla tego laboratorium, wykonując następujące polecenie:

Teraz użyjmy printf i wc do obliczenia rozmiaru naszego kodu powłoki:

Następnie użyjemy gdb, aby znaleźć miejsce, w którym należy wskazać EIP, aby wykonać nasz kod powłoki. Wiemy już, że możemy nadpisać EIP 412 bajtami, więc naszym pierwszym krokiem jest załadowanie i zawieszenie pliku binarnego z gdb. Aby to zrobić, wydamy następujące polecenie:

Następnie użyjemy gdb, aby znaleźć miejsce, w którym należy wskazać EIP, aby wykonać nasz kod powłoki. Wiemy już, że możemy nadpisać EIP 412 bajtami, więc naszym pierwszym krokiem jest załadowanie i zawieszenie pliku binarnego z gdb. Aby to zrobić, wydamy następujące polecenie:

Następnie użyjemy gdb, aby znaleźć miejsce, w którym należy wskazać EIP, aby wykonać nasz kod powłoki. Wiemy już, że możemy nadpisać EIP 412 bajtami, więc naszym pierwszym krokiem jest załadowanie i zawieszenie pliku binarnego z gdb. Aby to zrobić, wydamy następujące polecenie:

Shellcode

https://chacker.pl/

Shellcode to termin zarezerwowany dla kodu maszynowego, który wykona polecenia hakera. Pierwotnie termin ten został wymyślony, ponieważ celem złośliwego kodu było dostarczenie atakującemu prostej powłoki. Od tego czasu termin ten ewoluował, obejmując kod, który jest używany do zrobienia czegoś więcej niż dostarczenia powłoki, na przykład do podniesienia uprawnień lub wykonania pojedynczego polecenia w zdalnym systemie. Ważne jest, aby zdać sobie sprawę, że kod powłoki jest w rzeczywistości ciągiem binarnych kodów operacji dla eksploatowanej architektury (w tym przypadku Intel x86 32 bit), często reprezentowanych w formie szesnastkowej. W Internecie można znaleźć mnóstwo bibliotek kodu powłoki, gotowych do użycia na wszystkich  platformach. Użyjemy kodu powłoki Aleph1 (pokazanego w programie testowym) w następujący sposób:

Skompilujmy i uruchommy program testowy shellcode.c

Zadziałało — otrzymaliśmy powłokę główną.

NOP Sled

https://chacker.pl/

W kodzie asemblera polecenie NOP (no operation) oznacza po prostu, aby nic nie robić, tylko przejść do następnego polecenia. Hakerzy nauczyli się używać NOP do wypełnienia. Umieszczone na początku bufora exploita wypełnienie to nazywa się NOP sled. Jeśli EIP jest skierowane do NOP sled, procesor przesunie się na sled bezpośrednio do następnego komponentu. W systemach x86 kod operacji 0x90 oznacza NOP. W rzeczywistości jest ich znacznie więcej, ale 0x90 jest najczęściej używany. Każda sekwencja operacji, która nie koliduje z wynikiem exploita, byłaby uważana za równoważną NOP.