Uninitialized Variables

Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)!

Altri modi per supportare HackTricks:

Informazioni di Base

L'idea principale qui è capire cosa succede con le variabili non inizializzate poiché avranno il valore che era già presente nella memoria assegnata a loro. Esempio:

  • Funzione 1: initializeVariable: Dichiarando una variabile x e assegnandole un valore, diciamo 0x1234. Quest'azione è simile a riservare uno spazio in memoria e mettervi un valore specifico.

  • Funzione 2: useUninitializedVariable: Qui, dichiariamo un'altra variabile y ma non le assegnamo alcun valore. In C, le variabili non inizializzate non vengono automaticamente impostate a zero. Invece, mantengono il valore che era stato memorizzato per ultimo nella loro posizione di memoria.

Quando eseguiamo queste due funzioni in sequenza:

  1. In initializeVariable, x viene assegnata un valore (0x1234), che occupa un indirizzo di memoria specifico.

  2. In useUninitializedVariable, y viene dichiarata ma non viene assegnato alcun valore, quindi prende il posto di memoria subito dopo x. A causa della mancata inizializzazione di y, finisce per "ereditare" il valore dalla stessa posizione di memoria utilizzata da x, poiché è l'ultimo valore che c'era.

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 vulnerabilità di sicurezza, poiché potrebbero contenere involontariamente dati sensibili lasciati in memoria.

Le variabili non inizializzate nello stack potrebbero comportare diversi rischi per la sicurezza come:

  • Fuga di Dati: Informazioni sensibili come password, chiavi di crittografia o dettagli personali possono essere esposti se memorizzati in variabili non inizializzate, consentendo agli attaccanti di potenzialmente leggere questi dati.

  • Divulgazione di Informazioni: I contenuti delle variabili non inizializzate potrebbero rivelare dettagli sulla struttura di memoria del programma o sulle operazioni interne, aiutando gli attaccanti nello sviluppo di exploit mirati.

  • Blocchi e Instabilità: Operazioni che coinvolgono variabili non inizializzate possono comportare comportamenti non definiti, portando a blocchi del programma o a risultati imprevedibili.

  • Esecuzione di Codice Arbitrario: In determinati scenari, gli attaccanti potrebbero sfruttare queste vulnerabilità per alterare il flusso di esecuzione del programma, consentendo loro di eseguire codice arbitrario, che potrebbe includere minacce di esecuzione remota di codice.

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:

  • Funzione initializeAndPrint: Questa funzione dichiara una variabile intera initializedVar, le assegna il valore 100, e poi stampa sia l'indirizzo di memoria che il valore della variabile. Questo passaggio è diretto e mostra come si comporta una variabile inizializzata.

  • Funzione demonstrateUninitializedVar: In questa funzione, dichiariamo una variabile intera uninitializedVar senza inizializzarla. Quando tentiamo di stamparne il valore, l'output potrebbe mostrare un numero casuale. Questo numero rappresenta qualunque dato fosse precedentemente presente in quella posizione di memoria. A seconda dell'ambiente e del compilatore, l'output effettivo può variare e talvolta, per sicurezza, alcuni compilatori potrebbero inizializzare automaticamente le variabili a zero, anche se non ci si dovrebbe basare su questo.

  • Funzione main: La funzione main chiama entrambe le funzioni sopra in sequenza, dimostrando il contrasto tra una variabile inizializzata e una non inizializzata.

Esempio ARM64

Questo non cambia affatto in ARM64 poiché le variabili locali sono gestite anche nello stack, puoi controllare questo esempio dove ciò è mostrato.

Last updated