Stack Overflow

Nauka hakowania AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

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:

void vulnerable() {
char buffer[128];
printf("Enter some text: ");
gets(buffer); // This is where the vulnerability lies
printf("You entered: %s\n", buffer);
}

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:

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 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:

pageRet2win

Shellcode 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 Shellcode

ROP 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 Programing

Przepełnienia sterty

Przepełnienie nie zawsze musi wystąpić na stosie, może również wystąpić w stercie, na przykład:

pageHeap Overflow

Rodzaje zabezpieczeń

Istnieje kilka zabezpieczeń próbujących zapobiec eksploatacji podatności, sprawdź je tutaj:

pageCommon Binary Exploitation Protections & Bypasses

Last updated