Zugriff auf Speicherort vor Pufferanfang

Beschreibung

Zugriff auf Speicherort vor Pufferanfang ist eine Speichersicherheitsschwachstelle, bei der Software von einem Speicherort liest oder in einen schreibt, der dem Anfang eines allozierten Puffers vorausgeht. Dies tritt typischerweise auf, wenn ein Pointer oder Array-Index über die Startadresse des Puffers hinaus dekrementiert wird, wenn Zeigerarithmetik einen negativen Offset erzeugt, oder wenn ein negativer Index explizit verwendet wird. Auch bekannt als "Buffer Underread" oder "Buffer Underwrite" je nach Operation, kann diese Schwachstelle sensible Daten exponieren, Speicher korrumpieren oder Code-Ausführung ermöglichen.

Risiko

Der Zugriff auf Speicher vor einem Pufferanfang ist gefährlich, weil dieser Speicher sensible Daten, sicherheitskritische Werte oder komplett nicht gemappt sein kann. Lesen vor Pufferanfang kann sensible Informationen wie Passwörter, Schlüssel oder Speicherlayout-Details exponieren, die für Exploitation nützlich sind. Schreiben vor Pufferanfang korrumpiert angrenzende Datenstrukturen, möglicherweise einschließlich Funktionszeiger, Heap-Metadaten oder Sicherheitsflags. Die Schwachstelle ist besonders gefährlich, weil der zugriffene Speicher oft gültig ist und nicht sofort einen Absturz verursacht, was stille Korruption ermöglicht.

Lösung

Implementieren Sie Bounds-Checking bei allen Pufferzugriffen. Validieren Sie, dass Array-Indizes nicht-negativ sind vor der Verwendung. Seien Sie besonders vorsichtig mit Schleifen, die Indizes oder Pointer dekrementieren - stellen Sie sicher, dass sie am Pufferanfang stoppen. Verwenden Sie vorzeichenbehaftete Integer-Typen vorsichtig und validieren Sie, dass Werte nicht-negativ bleiben. Erwägen Sie die Verwendung sicherer Container-Klassen, die automatisches Bounds-Checking durchführen. Verwenden Sie Speichersicherheitstools wie AddressSanitizer während Entwicklung und Testing.

Häufige Auswirkungen

AuswirkungDetails
VertraulichkeitBereich: Vertraulichkeit

Speicher lesen - Underreads exponieren sensible Daten aus Speicher vor dem Puffer.
IntegritätBereich: Integrität

Speicher ändern - Underwrites korrumpieren Datenstrukturen angrenzend zum Puffer.
VerfügbarkeitBereich: Verfügbarkeit

DoS: Absturz - Speicherkorruption oder Zugriffsverletzungen verursachen Abstürze.
IntegritätBereich: Integrität

Unbefugten Code ausführen - Korrumpierte Funktionszeiger oder Heap-Metadaten ermöglichen Code-Ausführung.

Beispielcode

Verwundbarer Code

// Verwundbar: Index unter Null dekrementiert
char* trimTrailingWhitespace(char *strMessage, int length) {
    char *message = malloc(length + 1);
    if (!message) return NULL;

    memcpy(message, strMessage, length);
    message[length] = '\0';

    int index = length - 1;

    // Verwundbar: Wenn String nur Whitespace ist, wird index negativ
    while (isspace(message[index])) {
        message[index] = '\0';
        index--;
        // Keine Prüfung: index kann -1, -2 usw. werden
    }

    return message;
}

// Angriff: String "   " (nur Leerzeichen) übergeben
// index startet bei 2, dekrementiert zu -1, greift auf message[-1] zu
// Verwundbar: Negativer Array-Index aus Berechnung
void vulnerable_process_data(int* data, int size, int offset) {
    // Verwundbar: offset könnte negativ oder größer als erwartet sein
    for (int i = offset; i < size; i++) {
        // Wenn offset negativ ist, Zugriff vor data-Anfang
        data[i] = process(data[i]);
    }
}

// Verwundbar: Signed/Unsigned-Mismatch
void vulnerable_copy(char* dest, const char* src, int length) {
    // Verwundbar: wenn length negativ ist, underflow
    for (int i = length - 1; i >= 0; i--) {
        dest[i] = src[i];
    }
}
// Verwundbar: Benutzergesteuerter Index ohne Validierung
typedef struct {
    int values[10];
    char name[32];
} Record;

void vulnerable_set_value(Record* rec, int index, int value) {
    // Verwundbar: Keine Bounds-Prüfung auf index
    // Negativer Index greift auf Speicher vor values-Array zu
    rec->values[index] = value;
}

// Angriff: index = -1 überschreibt Speicher vor values[]

Gefixter Code

// Gefixt: Bounds-Checking bei Index-Dekrement
char* fixed_trimTrailingWhitespace(char *strMessage, int length) {
    if (length <= 0) {
        char* empty = malloc(1);
        if (empty) empty[0] = '\0';
        return empty;
    }

    char *message = malloc(length + 1);
    if (!message) return NULL;

    memcpy(message, strMessage, length);
    message[length] = '\0';

    int index = length - 1;

    // Gefixt: index >= 0 vor Zugriff prüfen
    while (index >= 0 && isspace((unsigned char)message[index])) {
        message[index] = '\0';
        index--;
    }

    return message;
}
// Gefixt: Offset vor Verwendung validieren
void fixed_process_data(int* data, int size, int offset) {
    // Gefixt: Validieren dass offset im gültigen Bereich ist
    if (offset < 0 || offset >= size) {
        return;  // Oder Fehler entsprechend behandeln
    }

    for (int i = offset; i < size; i++) {
        data[i] = process(data[i]);
    }
}

// Gefixt: size_t mit Underflow-Check verwenden
void fixed_copy(char* dest, const char* src, size_t length) {
    if (length == 0) return;

    // Gefixt: Vorwärts iterieren um Underflow-Probleme zu vermeiden
    for (size_t i = 0; i < length; i++) {
        dest[i] = src[i];
    }
}
// Gefixt: Array-Index validieren
typedef struct {
    int values[10];
    char name[32];
} Record;

bool fixed_set_value(Record* rec, int index, int value) {
    // Gefixt: Validieren dass index innerhalb Bounds ist
    if (index < 0 || index >= 10) {
        return false;  // Ungültiger Index
    }

    rec->values[index] = value;
    return true;
}

// Alternative: Unsigned-Typ verwenden und nur obere Grenze prüfen
bool fixed_set_value_v2(Record* rec, unsigned int index, int value) {
    if (index >= 10) {
        return false;  // Unsigned kann nicht negativ sein
    }

    rec->values[index] = value;
    return true;
}

CVE-Beispiele

  • CVE-2002-2227: SSLv2-Challenge-Wert-Behandlung verursachte Buffer-Underflow-Schwachstelle.
  • CVE-2007-4580: Buffer Underflow durch Größen/Längen-Inkonsistenz bei Datei-Parsing.
  • CVE-2007-1584: Underflow ausgelöst durch Verarbeitung von Strings, die nur Whitespace enthalten.
  • CVE-2006-4024: Negativer Parameter an memcpy übergeben verursacht Buffer Underflow.

Referenzen

  1. MITRE Corporation. "CWE-786: Access of Memory Location Before Start of Buffer." https://cwe.mitre.org/data/definitions/786.html
  2. CERT C Coding Standard. "ARR30-C. Do not form or use out-of-bounds pointers or array subscripts."
  3. CWE. "CWE-124: Buffer Underwrite ('Buffer Underflow')." Verwandte Schwachstelle.