Uninitialisierte Variablen

Reading time: 4 minutes

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Unterstützen Sie HackTricks

Grundinformationen

Die Kernidee hier ist zu verstehen, was mit uninitialisierten Variablen passiert, da sie den Wert haben, der bereits im zugewiesenen Speicher für sie war. Beispiel:

  • Funktion 1: initializeVariable: Wir deklarieren eine Variable x und weisen ihr einen Wert zu, sagen wir 0x1234. Diese Aktion ist vergleichbar mit der Reservierung eines Platzes im Speicher und dem Einfügen eines bestimmten Wertes darin.
  • Funktion 2: useUninitializedVariable: Hier deklarieren wir eine weitere Variable y, weisen ihr jedoch keinen Wert zu. In C werden uninitialisierte Variablen nicht automatisch auf null gesetzt. Stattdessen behalten sie den Wert, der zuletzt an ihrem Speicherort gespeichert wurde.

Wenn wir diese beiden Funktionen nacheinander ausführen:

  1. In initializeVariable wird x ein Wert (0x1234) zugewiesen, der einen bestimmten Speicherort belegt.
  2. In useUninitializedVariable wird y deklariert, aber nicht mit einem Wert belegt, sodass es den Speicherplatz direkt nach x einnimmt. Da y nicht initialisiert wurde, erbt es den Wert vom selben Speicherort, der von x verwendet wird, weil das der letzte Wert war, der dort war.

Dieses Verhalten veranschaulicht ein Schlüsselkonzept in der Low-Level-Programmierung: Speicherverwaltung ist entscheidend, und uninitialisierte Variablen können zu unvorhersehbarem Verhalten oder Sicherheitsanfälligkeiten führen, da sie unbeabsichtigt sensible Daten im Speicher halten können.

Uninitialisierte Stapelvariablen könnten mehrere Sicherheitsrisiken darstellen, wie:

  • Datenleckage: Sensible Informationen wie Passwörter, Verschlüsselungsschlüssel oder persönliche Details können offengelegt werden, wenn sie in uninitialisierten Variablen gespeichert sind, was Angreifern ermöglicht, diese Daten potenziell zu lesen.
  • Informationsoffenlegung: Der Inhalt uninitialisierter Variablen könnte Details über das Speicherlayout des Programms oder interne Abläufe offenbaren, was Angreifern hilft, gezielte Exploits zu entwickeln.
  • Abstürze und Instabilität: Operationen, die uninitialisierte Variablen betreffen, können zu undefiniertem Verhalten führen, was zu Programmabstürzen oder unvorhersehbaren Ergebnissen führt.
  • Willkürliche Codeausführung: In bestimmten Szenarien könnten Angreifer diese Schwachstellen ausnutzen, um den Ausführungsfluss des Programms zu ändern, was es ihnen ermöglicht, willkürlichen Code auszuführen, der möglicherweise Bedrohungen durch Remote-Code-Ausführung umfasst.

Beispiel

c
#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;
}

Wie das funktioniert:

  • initializeAndPrint Funktion: Diese Funktion deklariert eine Ganzzahlvariable initializedVar, weist ihr den Wert 100 zu und druckt dann sowohl die Speicheradresse als auch den Wert der Variable aus. Dieser Schritt ist unkompliziert und zeigt, wie sich eine initialisierte Variable verhält.
  • demonstrateUninitializedVar Funktion: In dieser Funktion deklarieren wir eine Ganzzahlvariable uninitializedVar, ohne sie zu initialisieren. Wenn wir versuchen, ihren Wert auszugeben, könnte die Ausgabe eine zufällige Zahl zeigen. Diese Zahl repräsentiert die Daten, die zuvor an diesem Speicherort waren. Je nach Umgebung und Compiler kann die tatsächliche Ausgabe variieren, und manchmal, zur Sicherheit, könnten einige Compiler Variablen automatisch auf null initialisieren, obwohl man sich darauf nicht verlassen sollte.
  • main Funktion: Die main Funktion ruft beide oben genannten Funktionen in Folge auf und demonstriert den Unterschied zwischen einer initialisierten und einer nicht initialisierten Variable.

ARM64 Beispiel

Das ändert sich überhaupt nicht in ARM64, da lokale Variablen ebenfalls im Stack verwaltet werden. Sie können dieses Beispiel überprüfen, wo dies gezeigt wird.

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Unterstützen Sie HackTricks