Stack Overflow

Support HackTricks

Co to jest Stack Overflow

Stack overflow to luka, która występuje, gdy program zapisuje więcej danych na stosie, niż jest przydzielone do przechowywania. Te nadmiarowe dane nadpiszą sąsiednią przestrzeń pamięci, prowadząc do uszkodzenia ważnych danych, zakłócenia przepływu sterowania i potencjalnie do wykonania złośliwego kodu. Problem ten często pojawia się z powodu użycia niebezpiecznych funkcji, które nie wykonują sprawdzania granic na wejściu.

Głównym problemem tego nadpisania jest to, że zapisany wskaźnik instrukcji (EIP/RIP) oraz zapisany wskaźnik bazowy (EBP/RBP) do powrotu do poprzedniej funkcji są przechowywane na stosie. Dlatego atakujący będzie w stanie nadpisać je i kontrolować przepływ wykonania programu.

Luka ta zazwyczaj pojawia się, ponieważ funkcja kopiuje na stos więcej bajtów niż ilość przydzielona dla niej, 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ż przydzielona.

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 offsetów przepełnienia stosu

Najczęstszym sposobem na znalezienie przepełnień stosu jest podanie bardzo dużego wejścia z As (np. python3 -c 'print("A"*1000)') i oczekiwanie na Segmentation Fault, co wskazuje, że adres 0x41414141 próbował być dostępny.

Ponadto, gdy już znajdziesz, że istnieje luka w przepełnieniu stosu, będziesz musiał znaleźć offset, aż będzie możliwe nadpisanie adresu powrotu, do tego zazwyczaj używa się sekwencji De Bruijn. Która dla danego alfabetu o rozmiarze k i podsekwencjach o długości n jest cykliczną sekwencją, w której każda możliwa podsekwencja o długości _n_** występuje dokładnie raz** jako kontiguująca podsekwencja.

W ten sposób, zamiast ręcznie ustalać, jaki offset jest potrzebny do kontrolowania EIP, można użyć jako wypełnienia jednej z tych sekwencji, a następnie znaleźć offset bajtów, które zakończyły nadpisanie.

Można użyć pwntools do tego:

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 (zakładając, że rozmiar przepełnienia jest wystarczająco duży) będziesz w stanie nadpisać wartości lokalnych zmiennych w stosie, aż do osiągnięcia zapisanych EBP/RBP i EIP/RIP (lub nawet więcej). Najczęstszym sposobem nadużywania tego typu podatności jest modyfikacja adresu powrotu, aby po zakończeniu funkcji przepływ kontroli został przekierowany tam, gdzie użytkownik wskazał w tym wskaźniku.

Jednak w innych scenariuszach może wystarczyć po prostu nadpisanie niektórych wartości zmiennych w stosie do wykorzystania (jak w łatwych wyzwaniach CTF).

Ret2win

W tego typu wyzwaniach CTF, istnieje funkcja wewnątrz binarnego pliku, która nigdy nie jest wywoływana i którą musisz wywołać, aby wygrać. W tych wyzwaniach musisz tylko znaleźć offset do nadpisania adresu powrotu i znaleźć adres funkcji, którą chcesz wywołać (zwykle ASLR będzie wyłączony), aby po powrocie z funkcji podatnej, ukryta funkcja została wywołana:

Ret2win

Shellcode na stosie

W tym scenariuszu atakujący mógłby umieścić shellcode w stosie i nadużyć kontrolowanego EIP/RIP, aby skoczyć do shellcode i wykonać dowolny kod:

Stack Shellcode

Techniki ROP i Ret2...

Ta technika jest podstawowym frameworkiem do obejścia głównej ochrony poprzedniej techniki: Brak wykonywalnego stosu (NX). Umożliwia to wykonanie kilku innych technik (ret2lib, ret2syscall...), które zakończą się wykonaniem dowolnych poleceń poprzez nadużycie istniejących instrukcji w binarnym pliku:

ROP - Return Oriented Programing

Przepełnienia sterty

Przepełnienie nie zawsze będzie miało miejsce w stosie, może również wystąpić w stercie, na przykład:

Heap Overflow

Rodzaje ochrony

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

Common Binary Exploitation Protections & Bypasses
Wsparcie dla HackTricks

Last updated