Variabili non inizializzate
Tip
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
Informazioni di base
Il concetto principale qui è capire cosa accade con le variabili non inizializzate, poiché assumeranno il valore che era già presente nella memoria assegnata a esse. Esempio:
- Funzione 1:
initializeVariable: Dichiariamo una variabilexe le assegniamo un valore, ad esempio0x1234. Questa azione è simile a riservare uno spazio in memoria e mettere un valore specifico al suo interno. - Funzione 2:
useUninitializedVariable: Qui dichiariamo un’altra variabileyma non le assegniamo alcun valore. In C, le variabili non inizializzate non vengono automaticamente impostate a zero. Invece, mantengono qualunque valore fosse stato memorizzato per ultimo nella loro locazione di memoria.
Quando eseguiamo queste due funzioni in sequenza:
- In
initializeVariable,xviene assegnato un valore (0x1234), che occupa un indirizzo di memoria specifico. - In
useUninitializedVariable,yviene dichiarata ma non le viene assegnato un valore, quindi occupa lo spazio di memoria immediatamente successivo ax. Poichéynon viene inizializzata, finisce per “ereditare” il valore proveniente dalla stessa locazione di memoria usata dax, perché è l’ultimo valore presente.
Questo comportamento illustra un concetto chiave nella programmazione a basso livello: la gestione della memoria è cruciale, e le variabili non inizializzate possono portare a comportamenti imprevedibili o a vulnerabilità di sicurezza, in quanto possono contenere involontariamente dati sensibili rimasti in memoria.
Le variabili di stack non inizializzate possono rappresentare diversi rischi per la sicurezza, come:
- Fuga di dati: Informazioni sensibili come password, chiavi di crittografia o dati personali possono essere esposte se memorizzate in variabili non inizializzate, consentendo ad attaccanti di leggere potenzialmente questi dati.
- Divulgazione di informazioni: Il contenuto delle variabili non inizializzate potrebbe rivelare dettagli sulla disposizione della memoria del programma o sulle sue operazioni interne, aiutando gli attaccanti a sviluppare exploit mirati.
- Crash e instabilità: Operazioni che coinvolgono variabili non inizializzate possono causare comportamenti indefiniti, portando a crash del programma o risultati imprevedibili.
- Esecuzione di codice arbitrario: In alcuni scenari, gli attaccanti potrebbero sfruttare queste vulnerabilità per alterare il flusso di esecuzione del programma, permettendo l’esecuzione di codice arbitrario, inclusa la possibilità di esecuzione di codice remoto.
Esempio
#include <stdio.h>
// Function to initialize and print a variable
void initializeAndPrint() {
int initializedVar = 100; // Initialize the variable
printf("Initialized Variable:\n");
printf("Address: %p, Value: %d\n\n", (void*)&initializedVar, initializedVar);
}
// Function to demonstrate the behavior of an uninitialized variable
void demonstrateUninitializedVar() {
int uninitializedVar; // Declare but do not initialize
printf("Uninitialized Variable:\n");
printf("Address: %p, Value: %d\n\n", (void*)&uninitializedVar, uninitializedVar);
}
int main() {
printf("Demonstrating Initialized vs. Uninitialized Variables in C\n\n");
// First, call the function that initializes its variable
initializeAndPrint();
// Then, call the function that has an uninitialized variable
demonstrateUninitializedVar();
return 0;
}
Come funziona:
initializeAndPrintFunction: Questa funzione dichiara una variabile interainitializedVar, le assegna il valore100, e poi stampa sia l’indirizzo di memoria sia il valore della variabile. Questo passaggio è semplice e mostra come si comporta una variabile inizializzata.demonstrateUninitializedVarFunction: In questa funzione dichiariamo una variabile interauninitializedVarsenza inizializzarla. Quando proviamo a stamparne il valore, l’output potrebbe mostrare un numero casuale. Questo numero rappresenta qualunque dato fosse precedentemente presente in quella locazione di memoria. A seconda dell’ambiente e del compiler, l’output effettivo può variare, e talvolta, per sicurezza, alcuni compiler possono inizializzare automaticamente le variabili a zero, anche se non bisognerebbe fare affidamento su questo comportamento.mainFunction: La funzionemainchiama entrambe le funzioni sopra in sequenza, dimostrando il contrasto tra una variabile inizializzata e una non inizializzata.
Pattern pratici di exploitation (2024–2025)
Il classico bug “read-before-write” rimane rilevante perché le mitigazioni moderne (ASLR, canaries) spesso si basano sulla segretezza. Superfici di attacco tipiche:
- Partially initialized structs copied to userland: Kernel o driver frequentemente eseguono
memsetsolo su un campo length e poicopy_to_user(&u, &local_struct, sizeof(local_struct)). Padding e campi inutilizzati leak stack canary halves, saved frame pointers o kernel pointers. Se la struct contiene un function pointer, lasciarlo uninitialized può anche permettere un controlled overwrite quando viene riutilizzato più tardi. - Uninitialized stack buffers reused as indexes/lengths: Un
size_t len;non inizializzato usato per limitareread(fd, buf, len)può dare agli attacker out-of-bounds reads/writes o permettere di bypassare i controlli di dimensione quando lo slot di stack contiene ancora un valore grande da una chiamata precedente. - Compiler-added padding: Anche quando i singoli membri sono inizializzati, i byte di padding impliciti tra di essi non lo sono. Copiare l’intera struct in userland leak padding che spesso contiene contenuti di stack precedenti (canaries, pointers).
- ROP/Canary disclosure: Se una funzione copia una struct locale su stdout per il debugging, il padding uninitialized può rivelare lo stack canary permettendo exploit di stack overflow successivi senza brute-force.
Minimal PoC pattern per rilevare tali problemi durante la revisione:
struct msg {
char data[0x20];
uint32_t len;
};
ssize_t handler(int fd) {
struct msg m; // never fully initialized
m.len = read(fd, m.data, sizeof(m.data));
// later debug helper
write(1, &m, sizeof(m)); // leaks padding + stale stack
return m.len;
}
Mitigazioni & compiler options (keep in mind when bypassing)
- Clang/GCC auto-init: Recent toolchains espongono
-ftrivial-auto-var-init=zeroor-ftrivial-auto-var-init=pattern, riempiendo ogni variabile automatica (stack) all’ingresso della funzione con zeri o un pattern tossico (0xAA / 0xFE). Questo chiude la maggior parte degli uninitialized-stack info leaks e rende l’exploitation più difficile convertendo i segreti in valori noti. - Linux kernel hardening: Kernels built with
CONFIG_INIT_STACK_ALLor the newerCONFIG_INIT_STACK_ALL_PATTERNzero/pattern-initialize every stack slot at function entry, wiping canaries/pointers che altrimenti causerebbero leak. Look for distros shipping Clang-built kernels with these options enabled (common in 6.8+ hardening configs). - Opt-out attributes: Clang now allows
__attribute__((uninitialized))on specific locals/structs to keep performance-critical areas uninitialized even when global auto-init is enabled. Review such annotations carefully—they often mark deliberate attack surface for side channels.
From an attacker perspective, knowing whether the binary was built with these flags determines if stack-leak primitives are viable or if you must pivot to heap/data-section disclosures.
Finding uninitialized-stack bugs quickly
- Compiler diagnostics: Build with
-Wall -Wextra -Wuninitialized(GCC/Clang). For C++ code,clang-tidy -checks=cppcoreguidelines-init-variableswill auto-fix many cases to zero-init and is handy to spot missed locals during audit. - Dynamic tools:
-fsanitize=memory(MSan) in Clang or Valgrind’s--track-origins=yesreliably flag reads of uninitialized stack bytes during fuzzing. Instrument test harnesses with these to surface subtle padding leaks. - Grepping patterns: In reviews, search for
copy_to_user/writecalls of whole structs, ormemcpy/sendof stack data where only part of the struct is set. Pay special attention to error paths where initialization is skipped.
ARM64 Example
This doesn’t change at all in ARM64 as local variables are also managed in the stack, you can check this example were this is shown.
References
- CONFIG_INIT_STACK_ALL_PATTERN documentation
- GHSL-2024-197: GStreamer uninitialized stack variable leading to function pointer overwrite
Tip
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.


