Wrap-around-Fehler

Beschreibung

Wrap-around-Fehler tritt auf, wenn ein Integer-Wert über seinen maximal darstellbaren Wert hinaus inkrementiert wird, wodurch er zu seinem Minimalwert "umwickelt" (oft Null oder eine große negative Zahl). Bei unsigned Integern wickelt das Inkrementieren über das Maximum zu Null um. Bei signed Integern ist das Overflow-Verhalten in C/C++ undefiniert, wickelt aber typischerweise zum minimalen negativen Wert um. Wrap-around-Fehler sind besonders gefährlich, wenn der betroffene Integer für sicherheitskritische Berechnungen wie Puffergrößen, Array-Indizes oder Schleifenzähler verwendet wird, was potenziell zu Buffer Overflows, Endlosschleifen oder anderer Speicherbeschädigung führt.

Risiko

Wrap-around-Fehler sind hochgradig ausnutzbar, weil sie große Werte in kleine oder negative Werte transformieren können und so Sicherheitsprüfungen umgehen. Ein klassischer Angriff beinhaltet das Bereitstellen eines großen Größenwerts, der zu einer kleinen Allokationsgröße umwickelt, gefolgt von Operationen, die die ursprüngliche große Größe annehmen—was zu massiven Buffer Overflows führt. Wrap-around bei Schleifenzählern kann Endlosschleifen oder vorzeitige Terminierung verursachen. Diese Schwachstellen haben Remote Code Execution in unzähligen Anwendungen ermöglicht, besonders solchen, die Netzwerkprotokolle, Dateiformate oder benutzerbereitgestellte Größenparameter verarbeiten.

Lösung

Validieren Sie Integer-Werte immer vor arithmetischen Operationen, die Wrap-around verursachen könnten. Verwenden Sie sichere Integer-Arithmetik-Bibliotheken, die Overflow erkennen (SafeInt in C++, checked arithmetic in Rust). Prüfen Sie auf Maximalwerte vor dem Inkrementieren. Verwenden Sie größere Integer-Typen, wenn möglich (64-bit statt 32-bit). Implementieren Sie explizite Overflow-Prüfungen vor Größenberechnungen, die bei Speicherallokation verwendet werden. Erwägen Sie Compiler-Flags, die bei Overflow abbrechen (-ftrapv in GCC). Vermeiden Sie unsigned Integers für Werte, die subtrahiert werden, da Underflow zu großen positiven Werten umwickelt.

Häufige Auswirkungen

AuswirkungDetails
IntegritätBereich: Speicherbeschädigung

Wrap-around bei Größenberechnungen führt zu unterdimensionierten Pufferallokationen und nachfolgenden Overflows, wenn der ursprüngliche Wert verwendet wird.
VerfügbarkeitBereich: Denial-of-Service

Wrap-around bei Schleifenzählern verursacht Endlosschleifen; Wrap-around bei Array-Indizes verursacht Abstürze.
ZugriffskontrolleBereich: Code-Ausführung

Buffer Overflows, die aus Wrap-around-Fehlern resultieren, können beliebige Code-Ausführung ermöglichen.

Beispielcode + Lösungscode

Anfälliger Code

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

// ANFÄLLIG: Integer-Wrap-around in Größenberechnung
void allocate_table(unsigned int num_entries) {
    // Wenn num_entries groß ist, wickelt Multiplikation um
    size_t size = num_entries * sizeof(int);  // Wickelt zu kleinem Wert um

    int *table = malloc(size);  // Allokiert winzigen Puffer

    // Späterer Code behandelt Tabelle als ob sie num_entries Elemente hätte
    for (unsigned int i = 0; i < num_entries; i++) {
        table[i] = 0;  // Massiver Buffer Overflow
    }
}

// ANFÄLLIG: Inkrement-Wrap-around
void process_loop(unsigned char count) {
    unsigned char i = 0;
    // Wenn count 255 ist und inkrementiert wird, wickelt zu 0 um
    while (i <= count) {
        process_item(i);
        i++;  // Wenn i=255, i++ wickelt zu 0, Schleife endet nie
    }
}

// ANFÄLLIG: Additions-Overflow in Grenzenprüfung
int safe_add_wrong(int a, int b, int *result) {
    // Diese Prüfung ist unzureichend - Overflow geschieht vor Vergleich
    if (a + b < a) {  // Undefiniertes Verhalten bei signed Overflow
        return -1;
    }
    *result = a + b;
    return 0;
}

Korrigierter Code

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

// SICHER: Auf Overflow vor Multiplikation prüfen
void *allocate_table_safe(size_t num_entries) {
    // Auf Multiplikations-Overflow prüfen
    if (num_entries > SIZE_MAX / sizeof(int)) {
        return NULL;  // Würde überläufen
    }

    size_t size = num_entries * sizeof(int);
    int *table = malloc(size);

    if (table) {
        memset(table, 0, size);  // Berechnete Größe verwenden
    }
    return table;
}

// SICHER: Wrap-around in Schleife vermeiden
void process_loop_safe(unsigned int count) {
    for (unsigned int i = 0; i < count; i++) {
        process_item(i);
    }
    // Letztes Element separat behandeln falls nötig
    if (count > 0) {
        process_item(count);
    }
}

// SICHER: Auf Overflow vor Arithmetik prüfen
int safe_add(int a, int b, int *result) {
    // Vor Durchführung der Addition prüfen
    if (b > 0 && a > INT_MAX - b) {
        return -1;  // Würde überläufen
    }
    if (b < 0 && a < INT_MIN - b) {
        return -1;  // Würde unterlaufen
    }
    *result = a + b;
    return 0;
}

// SICHER: size_t für Größen verwenden und Overflow prüfen
size_t safe_multiply(size_t a, size_t b) {
    if (a != 0 && b > SIZE_MAX / a) {
        return 0;  // Overflow, Fehlerindikator zurückgeben
    }
    return a * b;
}

Ausgenutzt in der Praxis

OpenSSH Challenge-Response (OpenSSH, 2002)

CVE-2002-0639 war ein Integer-Overflow in OpenSSHs Challenge-Response-Authentifizierung, der Remote-Angreifern erlaubte, beliebigen Code auszuführen, indem sie Wrap-around in einer Größenberechnung ausnutzten.

Windows-Bildverarbeitung (Microsoft, mehrfach)

Mehrere Integer-Overflow-Schwachstellen in Windows GDI+ und Bildverarbeitungsbibliotheken wurden durch bösartige Bilddateien mit manipulierten Dimensionswerten ausgenutzt, die Wrap-around verursachen.

PNG-Bibliothek Integer-Overflow (libpng, 2015)

CVE-2015-8126 war ein Integer-Overflow in libpng, der zu Heap-Buffer-Overflows führen könnte, wenn PNG-Bilder mit bösartig gestalteten Chunk-Größen verarbeitet wurden.


Tools zum Testen/Ausnutzen

  • UBSan — Undefined-Behavior-Sanitizer, der signed Integer-Overflow erkennt.

  • SafeInt — C++-Bibliothek für sichere Integer-Arithmetik mit Overflow-Erkennung.

  • AFL++ — Fuzzer, der effektiv bei der Entdeckung von Integer-Overflow-Bedingungen ist.


CVE-Beispiele

  • CVE-2002-0639 — OpenSSH Integer-Overflow in Challenge-Response-Authentifizierung.

  • CVE-2015-8126 — libpng Integer-Overflow führt zu Buffer Overflow.

  • CVE-2021-21300 — Git Integer-Overflow ermöglicht RCE auf case-insensitiven Dateisystemen.


Referenzen

  1. MITRE. "CWE-128: Wrap-around Error." https://cwe.mitre.org/data/definitions/128.html

  2. CERT. "INT30-C. Ensure that unsigned integer operations do not wrap." https://wiki.sei.cmu.edu/confluence/display/c/INT30-C