.. | ||
ret2lib | ||
ebp2ret-ebp-chaining.md | ||
pointer-redirecting.md | ||
README.md | ||
ret2csu.md | ||
ret2dlresolve.md | ||
ret2esp-ret2reg.md | ||
ret2ret.md | ||
ret2shellcode.md | ||
ret2win.md | ||
rop-return-oriented-programing.md | ||
rop-syscall-execv.md | ||
srop-sigreturn-oriented-programming.md | ||
stack-pivoting-ebp2ret-ebp-chaining.md | ||
stack-shellcode.md |
Przepełnienie stosu
Nauka hakowania AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!
Inne sposoby wsparcia HackTricks:
- Jeśli chcesz zobaczyć swoją firmę reklamowaną w HackTricks lub pobrać HackTricks w formacie PDF, sprawdź PLANY SUBSKRYPCYJNE!
- Zdobądź oficjalne gadżety PEASS & HackTricks
- Odkryj Rodzinę PEASS, naszą kolekcję ekskluzywnych NFT
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Podziel się swoimi sztuczkami hakowania, przesyłając PR-y do HackTricks i HackTricks Cloud github repos.
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 spowodują nadpisanie sąsiedniego obszaru 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ą sprawdzania granic danych wejściowych.
Głównym problemem tego nadpisania jest to, że wskaźniki EIP i EBP do powrotu do poprzedniej funkcji są przechowywane na stosie. Dlatego atakujący będzie mógł nadpisać te wskaźniki i kontrolować przepływ wykonania programu.
Podatność zazwyczaj pojawia się, gdy funkcja kopiuję na stos więcej bajtów niż jest na nią zaalokowane, co pozwala na nadpisanie innych części stosu.
Niektóre powszechne funkcje podatne na to to: strcpy
, strcat
, sprintf
, gets
, fgets
...
Na przykład, następujące funkcje mogą być podatne:
void vulnerable() {
char buffer[128];
printf("Enter some text: ");
gets(buffer); // This is where the vulnerability lies
printf("You entered: %s\n", buffer);
}
Znajdowanie przepełnień stosu
Najczęstszym sposobem na znalezienie przepełnień 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 wskaźnika EIP, 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, które przesunięcie nadpisuje EIP, można użyć jednego z tych ciągów jako dopełnienia, a następnie znaleźć przesunięcie bajtów, które skończyły nadpisywać go.
Można to zrobić za pomocą pwntools:
from pwn import *
# Generate a De Bruijn sequence of length 1000 with an alphabet size of 256 (byte values)
pattern = cyclic(1000)
# This is an example value that you'd have found in the EIP/IP register upon crash
eip_value = p32(0x6161616c)
offset = cyclic_find(eip_value) # Finds the offset of the sequence in the De Bruijn pattern
print(f"The offset is: {offset}")
lub GEF:
#Patterns
pattern create 200 #Generate length 200 pattern
pattern search "avaaawaa" #Search for the offset of that substring
pattern search $rsp #Search the offset given the content of $rsp
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 innych zmiennych w stosie aż do osiągnięcia EBP i EIP (lub nawet więcej).
Najczęstszym sposobem nadużycia tego rodzaju podatności jest modyfikacja wskaźnika EIP, dzięki czemu po zakończeniu funkcji przepływ sterowania zostanie przekierowany w miejsce, które użytkownik określił w tym wskaźniku.
Jednakże, w innych scenariuszach może wystarczyć nadpisanie wartości niektórych zmiennych w 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 EIP 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:
{% content-ref url="ret2win.md" %} ret2win.md {% endcontent-ref %}
Shellcode na stosie
W tym scenariuszu atakujący może umieścić shellcode na stosie i nadużyć kontrolowanego EIP, aby przejść do shellcode i wykonać kod atakującego:
{% content-ref url="stack-shellcode.md" %} stack-shellcode.md {% endcontent-ref %}
ROP
Ta technika jest podstawowym narzędziem do obejścia głównej ochrony poprzedniej techniki: Brak wykonalnego stosu. Pozwala ona na wykonanie kilku innych technik (ret2lib, ret2syscall...), które ostatecznie wykonają dowolne polecenia, nadużywając istniejących instrukcji w binariach:
{% content-ref url="rop-return-oriented-programing.md" %} rop-return-oriented-programing.md {% endcontent-ref %}
Rodzaje zabezpieczeń
Istnieje kilka zabezpieczeń próbujących zapobiec wykorzystaniu podatności, sprawdź je tutaj:
{% content-ref url="../common-binary-protections-and-bypasses/" %} common-binary-protections-and-bypasses {% endcontent-ref %}