Buffer Under-read

Beschreibung

Buffer Under-read tritt auf, wenn ein Programm Daten von Speicherstellen vor dem Anfang eines beabsichtigten Puffers liest. Dies geschieht typischerweise, wenn ein Pointer oder Array-Index unter Null dekrementiert wird, Pointer-Arithmetik einen negativen Offset produziert oder ein negativer Index für Array-Zugriff verwendet wird. Anders als Buffer Overflows verursachen Under-reads primär Informationsoffenlegung, indem sie Daten aus Speicher vor dem Zielpuffer offenlegen. Dies kann sensible Informationen aus anderen Variablen, Heap-Metadaten oder zuvor freigegebenen Speicherinhalten umfassen.

Risiko

Buffer Under-reads stellen Vertraulichkeitsrisiken dar, indem sie potenziell sensible Daten offenlegen, die in Speicherstellen vor dem Zielpuffer gespeichert sind. Obwohl typischerweise weniger schwerwiegend als Buffer Overflows, können Under-reads kryptografische Schlüssel, Passwörter oder andere Geheimnisse leaken, die in angrenzendem Speicher gespeichert sind. In einigen Fällen können Under-reads Abstürze verursachen, wenn sie auf nicht gemappte Speicherbereiche zugreifen, was zu Denial-of-Service führt. Die Schwachstelle kann auch mit anderen Schwächen kombiniert werden, um schwerwiegendere Exploitation-Ergebnisse zu erzielen.

Lösung

Validieren Sie alle Array-Indizes und Pointer-Offsets vor der Verwendung und prüfen Sie sowohl obere als auch untere Grenzen. Verwenden Sie unsigned Integer-Typen für Array-Indizes, wo negative Werte logisch ungültig sind. Implementieren Sie grenzenprüfende Wrapper-Funktionen für Pufferzugriff. Verwenden Sie speichersichere Sprachen oder C++-Container, die Out-of-bounds-Zugriff verhindern. Aktivieren Sie AddressSanitizer während der Entwicklung, um Under-reads zu erkennen. Überprüfen Sie Pointer-Arithmetik-Operationen, besonders solche mit Subtraktions- oder Dekrementierungsoperationen.

Häufige Auswirkungen

AuswirkungDetails
VertraulichkeitBereich: Informationsoffenlegung

Das Lesen von Speicher vor dem Pufferstart kann sensible Daten aus anderen Variablen oder Datenstrukturen offenlegen.
VerfügbarkeitBereich: Verfügbarkeit

Der Zugriff auf nicht gemappte Speicherseiten verursacht Segmentation Faults und Abstürze.
IntegritätBereich: Informationsleck

Geleakte Informationen können Angreifern helfen, Sicherheitsmechanismen zu umgehen oder andere Schwachstellen auszunutzen.

Beispielcode + Lösungscode

Anfälliger Code

#include <string.h>
#include <stdlib.h>

// ANFÄLLIG: Negativer Index-Under-read
int get_previous_value(int *array, int current_index) {
    // Keine Prüfung auf negatives Ergebnis
    return array[current_index - 1];  // Under-read wenn current_index == 0
}

// ANFÄLLIG: Pointer-Dekrement-Under-read
char *find_start_of_line(char *buffer, char *current_pos) {
    // Dekrement ohne Prüfung der Puffergrenze
    while (*current_pos != '\n') {
        current_pos--;  // Kann vor Pufferstart gehen
    }
    return current_pos + 1;
}

// ANFÄLLIG: Negativer Offset aus Konfiguration
void read_at_offset(char *buffer, int offset) {
    // Benutzergesteuerter Offset könnte negativ sein
    char value = buffer[offset];  // Under-read wenn offset < 0
    process(value);
}

Korrigierter Code

#include <string.h>
#include <stdlib.h>
#include <stdbool.h>

// SICHER: Grenzenprüfung vor Zugriff
bool get_previous_value_safe(int *array, size_t array_size,
                             size_t current_index, int *out_value) {
    // Prüfen, dass es ein vorheriges Element GIBT
    if (current_index == 0 || current_index > array_size) {
        return false;  // Kein gültiges vorheriges Element
    }
    *out_value = array[current_index - 1];
    return true;
}

// SICHER: Puffergrenzen prüfen
char *find_start_of_line_safe(char *buffer_start, char *buffer_end,
                              char *current_pos) {
    // Validieren, dass current_pos innerhalb des Puffers ist
    if (current_pos < buffer_start || current_pos >= buffer_end) {
        return NULL;
    }

    // Am Pufferstart stoppen
    while (current_pos > buffer_start && *current_pos != '\n') {
        current_pos--;
    }

    // Position nach Newline zurückgeben (oder Pufferstart)
    return (current_pos == buffer_start) ? current_pos : current_pos + 1;
}

// SICHER: Validieren, dass Offset nicht negativ ist
bool read_at_offset_safe(const char *buffer, size_t buffer_size,
                         size_t offset, char *out_value) {
    // size_t ist unsigned, aber obere Grenze auch prüfen
    if (offset >= buffer_size) {
        return false;
    }
    *out_value = buffer[offset];
    return true;
}

Ausgenutzt in der Praxis

c-ares DNS-Bibliothek (Mehrere Systeme, 2024)

CVE-2024-25629 ist eine Buffer-Under-read-Schwachstelle in der c-ares-C-Bibliothek für asynchrone DNS-Anfragen. Ein NULL-Zeichen am Anfang einer neuen Zeile in Konfigurationsdateien (/etc/resolv.conf, /etc/nsswitch.conf) könnte Lesezugriffe vor dem Pufferstart verursachen und zu Abstürzen führen. Die Schwachstelle betraf IBM Storage Ceph, Node.js und viele Linux-Distributionen.

Mehrere Herstellerprodukte (Verschiedene, fortlaufend)

Buffer-Under-read-Schwachstellen werden weiterhin in verschiedenen Produkten entdeckt, einschließlich Medien-Codecs, Netzwerkprotokoll-Parsern und Dateiformat-Handlern, was typischerweise zu Informationsoffenlegung oder Denial-of-Service führt.


Tools zum Testen/Ausnutzen

  • AddressSanitizer — erkennt Buffer Under-reads zur Laufzeit mit präziser Fehlermeldung.

  • Valgrind — Speicherfehlerdetektor, der Lesezugriffe vor allokiertem Speicher identifiziert.

  • AFL++ — Fuzzer, der effektiv bei der Entdeckung von Grenzbedingungsfehlern ist.


CVE-Beispiele

  • CVE-2024-25629 — c-ares Buffer Under-read verursacht Denial-of-Service.

  • CVE-2023-52160 — wpa_supplicant Buffer Under-read in EAP-TLS-Verarbeitung.

  • CVE-2021-3449 — OpenSSL NULL-Pointer-Dereferenzierung aus Under-read-Bedingung.


Referenzen

  1. MITRE. "CWE-127: Buffer Under-read." https://cwe.mitre.org/data/definitions/127.html

  2. CERT. "ARR30-C. Do not form or use out-of-bounds pointers or array subscripts." https://wiki.sei.cmu.edu/confluence/display/c/ARR30-C