Unsachgemäße Kontrolle der sequentiellen Speicherallokation

Beschreibung

Unsachgemäße Kontrolle der sequentiellen Speicherallokation tritt auf, wenn ein Produkt Ressourcen sequentiell allokiert, ohne Grenzen oder Drosselung zu setzen, was zu unkontrolliertem Ressourcenverbrauch führen kann. Wenn ein Angreifer viele Ressourcen-Allokationen auslösen kann, ohne entsprechende Freigabe, kann er den verfügbaren Speicher oder andere Systemressourcen erschöpfen, was zu Denial of Service führt. Dieses Problem tritt häufig bei Speicherallokationen, Datei-Handle-Zuweisungen oder Verbindungspools auf, bei denen das System die kumulative Ressourcennutzung nicht begrenzt.

Risiko

Unkontrollierte sequentielle Allokation erzeugt erhebliche Risiken. Speichererschöpfungsangriffe können Anwendungen oder Systeme zum Absturz bringen. Ressourcenaushungerung beeinträchtigt andere Prozesse auf dem System. Angreifer können niedrige Allokationsraten verwenden, um der Erkennung zu entgehen, während sie allmählich Ressourcen erschöpfen. Die kumulative Wirkung vieler kleiner Allokationen kann schwerer zu erkennen sein als einzelne große Allokationen.

Lösung

Implementieren Sie Grenzen für die Gesamtressourcen-Allokation pro Benutzer oder Sitzung. Verwenden Sie Speicherpools mit festen Größen. Setzen Sie Timeouts für Ressourcen-Haltedauer. Implementieren Sie Überwachung für Ressourcenverbrauchsmuster. Verwenden Sie Ratenbegrenzung für ressourcenintensive Operationen. Stellen Sie die ordnungsgemäße Ressourcenfreigabe in allen Codepfaden sicher.

Häufige Auswirkungen

AuswirkungDetails
VerfügbarkeitBereich: Verfügbarkeit

DoS: Ressourcenverbrauch - Angreifer können verfügbare Systemressourcen durch wiederholte Allokation erschöpfen.

Beispielcode und Lösung

Verwundbarer Code

// Verwundbar: Unbegrenzte Speicherallokation in C
#include <stdlib.h>
#include <string.h>

// VERWUNDBAR: Keine Begrenzung der Allokationsanzahl
struct Nachricht* nachrichten_liste = NULL;
int nachrichten_anzahl = 0;

// VERWUNDBAR: Jeder Aufruf allokiert ohne Grenze
void nachricht_hinzufügen(const char* inhalt) {
    struct Nachricht* neu = malloc(sizeof(struct Nachricht));
    neu->inhalt = strdup(inhalt);  // Weitere Allokation ohne Prüfung
    neu->nächste = nachrichten_liste;
    nachrichten_liste = neu;
    nachrichten_anzahl++;  // Keine obere Grenze!
}

// VERWUNDBAR: Unbegrenzte Puffer-Wachstum
char* verwundbar_lese_alles(int fd) {
    char* puffer = NULL;
    size_t gesamt = 0;
    char temp[1024];
    ssize_t gelesen;

    while ((gelesen = read(fd, temp, sizeof(temp))) > 0) {
        // VERWUNDBAR: Unbegrenztes Wachstum
        puffer = realloc(puffer, gesamt + gelesen);
        memcpy(puffer + gesamt, temp, gelesen);
        gesamt += gelesen;
    }

    return puffer;
}
# Verwundbar: Unbegrenzte Sammlung in Python
class VerwundbarerCache:
    def __init__(self):
        # VERWUNDBAR: Unbegrenzter Cache
        self.cache = {}

    def hinzufügen(self, schlüssel, wert):
        # VERWUNDBAR: Keine Grenze für Cache-Einträge
        self.cache[schlüssel] = wert

    def holen(self, schlüssel):
        return self.cache.get(schlüssel)

# VERWUNDBAR: Unbegrenzte Listen-Akkumulation
class VerwundbarerLogger:
    def __init__(self):
        self.logs = []  # Wächst unbegrenzt

    def log(self, nachricht):
        # VERWUNDBAR: Logs werden nie bereinigt
        self.logs.append({
            'zeit': time.time(),
            'nachricht': nachricht
        })

# VERWUNDBAR: Unbegrenzte Sitzungsspeicherung
sitzungen = {}

def sitzung_erstellen(benutzer_id):
    # VERWUNDBAR: Alte Sitzungen werden nie entfernt
    sitzung_id = generiere_sitzung_id()
    sitzungen[sitzung_id] = {
        'benutzer': benutzer_id,
        'daten': {}
    }
    return sitzung_id

Sichere Lösung

// Sicher: Begrenzte Speicherallokation in C
#include <stdlib.h>
#include <string.h>

#define MAX_NACHRICHTEN 1000
#define MAX_NACHRICHT_GROESSE 4096
#define MAX_PUFFER_GROESSE (10 * 1024 * 1024)  // 10MB

struct Nachricht* nachrichten_liste = NULL;
int nachrichten_anzahl = 0;

// Sicher: Begrenzte Allokation
int nachricht_hinzufügen(const char* inhalt) {
    // Sicher: Grenze prüfen
    if (nachrichten_anzahl >= MAX_NACHRICHTEN) {
        return -1;  // Grenze erreicht
    }

    // Sicher: Nachrichtengröße begrenzen
    size_t länge = strlen(inhalt);
    if (lange > MAX_NACHRICHT_GROESSE) {
        return -1;  // Zu groß
    }

    struct Nachricht* neu = malloc(sizeof(struct Nachricht));
    if (!neu) return -1;

    neu->inhalt = malloc(lange + 1);
    if (!neu->inhalt) {
        free(neu);
        return -1;
    }

    memcpy(neu->inhalt, inhalt, länge + 1);
    neu->nächste = nachrichten_liste;
    nachrichten_liste = neu;
    nachrichten_anzahl++;

    return 0;
}

// Sicher: Begrenztes Pufferlesen
char* sicher_lese_begrenzt(int fd, size_t max_große) {
    if (max_große > MAX_PUFFER_GROESSE) {
        max_große = MAX_PUFFER_GROESSE;
    }

    char* puffer = malloc(max_große);
    if (!puffer) return NULL;

    size_t gesamt = 0;
    char temp[1024];
    ssize_t gelesen;

    while ((gelesen = read(fd, temp, sizeof(temp))) > 0) {
        // Sicher: Grenze prüfen
        if (gesamt + gelesen > max_große) {
            free(puffer);
            return NULL;  // Würde Grenze überschreiten
        }

        memcpy(puffer + gesamt, temp, gelesen);
        gesamt += gelesen;
    }

    return puffer;
}
# Sicher: Begrenzter Cache in Python
from collections import OrderedDict
import time
import threading

class SichererCache:
    def __init__(self, max_große=1000, ttl_sekunden=3600):
        self.max_große = max_große
        self.ttl = ttl_sekunden
        self.cache = OrderedDict()
        self.lock = threading.Lock()

    def hinzufügen(self, schlüssel, wert):
        with self.lock:
            # Sicher: Abgelaufene Einträge entfernen
            self._bereinigen()

            # Sicher: LRU-Räumung wenn voll
            while len(self.cache) >= self.max_große:
                self.cache.popitem(last=False)

            self.cache[schlüssel] = {
                'wert': wert,
                'erstellt': time.time()
            }

    def _bereinigen(self):
        jetzt = time.time()
        abgelaufen = [k for k, v in self.cache.items()
                      if jetzt - v['erstellt'] > self.ttl]
        for k in abgelaufen:
            del self.cache[k]

# Sicher: Begrenzter Sitzungsmanager
class SichererSitzungsManager:
    MAX_SITZUNGEN = 10000
    SITZUNGS_TIMEOUT = 3600

    def __init__(self):
        self.sitzungen = {}
        self.lock = threading.Lock()

    def sitzung_erstellen(self, benutzer_id):
        with self.lock:
            # Sicher: Alte Sitzungen bereinigen
            self._abgelaufene_bereinigen()

            # Sicher: Grenze erzwingen
            if len(self.sitzungen) >= self.MAX_SITZUNGEN:
                # Älteste Sitzungen entfernen
                self._aelteste_entfernen(100)

            sitzung_id = self._generiere_id()
            self.sitzungen[sitzung_id] = {
                'benutzer': benutzer_id,
                'erstellt': time.time(),
                'letzter_zugriff': time.time()
            }
            return sitzung_id

    def _abgelaufene_bereinigen(self):
        jetzt = time.time()
        abgelaufen = [sid for sid, data in self.sitzungen.items()
                      if jetzt - data['letzter_zugriff'] > self.SITZUNGS_TIMEOUT]
        for sid in abgelaufen:
            del self.sitzungen[sid]

Ausgenutzt in der Praxis

Speichererschöpfungs-DoS in Webservern

Angreifer haben Speichererschöpfungsangriffe gegen Webserver durchgeführt, indem sie viele kleine Anfragen sendeten, die jeweils Speicher allokierten, ohne ihn freizugeben, was zum Serverabsturz führte.

ZIP-Bomben und Dekomprimierungsangriffe

Komprimierte Dateien, die zu riesigen Datenmengen dekomprimieren, nutzen unbegrenzte Allokation aus, um Systemspeicher zu erschöpfen.


Tools zum Testen und Ausnutzen


CVE-Beispiele

  • CVE-2018-6389 - WordPress Load-Scripts-DoS über unbegrenzte Ressourcenladung.

  • CVE-2020-8908 - Guava erstellt temporäre Verzeichnisse ohne Grenzen.


Referenzen

  1. MITRE Corporation. "CWE-1325: Improperly Controlled Sequential Memory Allocation." https://cwe.mitre.org/data/definitions/1325.html

  2. OWASP. "Memory Exhaustion." https://owasp.org/www-community/vulnerabilities/Memory_Exhaustion

  3. CWE. "CWE-400: Uncontrolled Resource Consumption." https://cwe.mitre.org/data/definitions/400.html