Stack Overflow
Co to jest przepełnienie stosu
Przepełnienie stosu to podatność, która występuje, gdy program zapisuje więcej danych na stosie, niż jest mu przydzielone do przechowywania. Nadmiarowe dane nadpisują sąsiednie miejsce w pamięci, prowadząc do uszkodzenia poprawnych danych, zakłócenia przepływu sterowania i potencjalnie wykonania złośliwego kodu. Ten problem często wynika z użycia funkcji niebezpiecznych, które nie wykonują kontroli granic danych wejściowych.
Głównym problemem tego nadpisania jest to, że zachowany wskaźnik instrukcji (EIP/RIP) i zachowany wskaźnik bazowy (EBP/RBP) do powrotu do poprzedniej funkcji są przechowywane na stosie. Dlatego atakujący będzie mógł nadpisać te wartości i kontrolować przepływ wykonania programu.
Podatność zazwyczaj pojawia się, gdy funkcja kopiuję na stos więcej bajtów niż jest na niego zaalokowane, co pozwala na nadpisanie innych części stosu.
Niektóre powszechne funkcje podatne na to to: strcpy
, strcat
, sprintf
, gets
... Ponadto funkcje takie jak fgets
, read
& memcpy
, które przyjmują argument długości, mogą być używane w sposób podatny, jeśli określona długość jest większa niż zaalokowana.
Na przykład, następujące funkcje mogą być podatne:
Znajdowanie przesunięć Stack Overflows
Najczęstszym sposobem na znalezienie przepełnienia stosu jest podanie bardzo dużego wejścia z literami A
(np. python3 -c 'print("A"*1000)'
) i oczekiwanie Segmentation Fault
, co wskazuje, że próbowano uzyskać dostęp do adresu 0x41414141
.
Ponadto, po znalezieniu podatności na przepełnienie stosu, konieczne będzie znalezienie przesunięcia, aż będzie możliwe nadpisanie adresu powrotu, do tego zazwyczaj używany jest ciąg De Bruijna. Dla danego alfabetu o rozmiarze k i podciągów o długości n, jest to cykliczny ciąg, w którym każdy możliwy podciąg o długości n** pojawia się dokładnie raz** jako ciągły podciąg.
W ten sposób, zamiast ręcznego określania wymaganego przesunięcia do kontrolowania EIP, można użyć jednego z tych ciągów jako dopełnienia, a następnie znaleźć przesunięcie bajtów, które nadpisały go.
Można to zrobić za pomocą pwntools:
lub GEF:
Wykorzystywanie przepełnień stosu
Podczas przepełnienia (przy założeniu, że rozmiar przepełnienia jest wystarczająco duży) będziesz mógł nadpisać wartości zmiennych lokalnych na stosie aż do osiągnięcia zapisanych EBP/RBP i EIP/RIP (lub nawet więcej). Najczęstszym sposobem wykorzystania tego rodzaju podatności jest modyfikacja adresu powrotu, więc gdy funkcja się kończy, przepływ sterowania zostanie przekierowany w miejsce, które użytkownik określił w tym wskaźniku.
Jednakże, w innych scenariuszach może być wystarczające jedynie nadpisanie wartości niektórych zmiennych na stosie dla eksploatacji (jak w łatwych wyzwaniach CTF).
Ret2win
W tego rodzaju wyzwaniach CTF, istnieje funkcja wewnątrz binariów, która nigdy nie jest wywoływana i musisz ją wywołać, aby wygrać. W tych wyzwaniach wystarczy znaleźć przesunięcie do nadpisania adresu powrotu i znaleźć adres funkcji do wywołania (zwykle ASLR byłoby wyłączone), więc gdy podatna funkcja zakończy działanie, ukryta funkcja zostanie wywołana:
pageRet2winShellcode na stosie
W tym scenariuszu atakujący może umieścić shellcode na stosie i wykorzystać kontrolowany EIP/RIP, aby przeskoczyć do shellcode i wykonać dowolny kod:
pageStack ShellcodeROP i techniki Ret2...
Ta technika stanowi podstawową strukturę do obejścia głównej ochrony poprzedniej techniki: Brak wykonalnego stosu (NX). I pozwala na wykonanie kilku innych technik (ret2lib, ret2syscall...), które zakończą się wykonaniem dowolnych poleceń poprzez nadużywanie istniejących instrukcji w binariach:
pageROP - Return Oriented ProgramingPrzepełnienia sterty
Przepełnienie nie zawsze musi wystąpić na stosie, może również wystąpić w stercie, na przykład:
pageHeap OverflowRodzaje zabezpieczeń
Istnieje kilka zabezpieczeń próbujących zapobiec eksploatacji podatności, sprawdź je tutaj:
pageCommon Binary Exploitation Protections & BypassesLast updated