Asymmetrischer Ressourcenverbrauch (Amplifikation)

Beschreibung

Asymmetrischer Ressourcenverbrauch (Amplifikation) ist eine Schwachstelle, die auftritt, wenn ein Produkt Situationen nicht ordnungsgemäß kontrolliert, in denen ein Angreifer das Produkt dazu bringen kann, übermäßige Ressourcen zu verbrauchen oder zu produzieren, ohne dass der Angreifer äquivalente Arbeit oder Ressourcen investieren muss. Dies erzeugt schlechte Leistung durch nicht-lineare Ressourcenverstärkung, bei der kleine Angreifer-Eingaben unverhältnismäßig großen Ressourcenverbrauch verursachen. Häufige Beispiele sind DNS-Amplifikationsangriffe, XML-Bomben und algorithmische Komplexitätsangriffe.

Risiko

Asymmetrischer Ressourcenverbrauch ermöglicht hocheffektive Denial-of-Service-Angriffe. Angreifer können Server-Ressourcen (CPU, Speicher, Bandbreite) mit minimalem Investment erschöpfen. Bei DNS-Amplifikationsangriffen generieren kleine Anfragen große Antworten, die an Opfer gerichtet werden. XML-Entity-Expansion (Billion-Laughs-Angriff) kann Kilobytes an Eingabe zu Gigabytes an Speicher expandieren. Algorithmische Komplexitätsangriffe können O(n)-Operationen in O(n²) oder exponentielle Zeit verwandeln. Diese Angriffe sind besonders gefährlich, weil sie minimale Angreifer-Ressourcen erfordern, während sie den Ressourcenverbrauch des Opfers maximieren, was sie wirtschaftlich tragfähig für Angreifer macht.

Lösung

Allozieren Sie Ressourcen entsprechend den Clientzugriffsstufen. Verfolgen und messen Sie Ressourcenverbrauch angemessen. Implementieren Sie Rate-Limiting und Request-Throttling. Deaktivieren Sie ressourcenintensive Algorithmen auf Servern wo möglich. Setzen Sie strenge Limits für Entity-Expansion in XML-Parsern. Verwenden Sie lineare Algorithmen wo möglich. Validieren Sie Eingabegrößen vor der Verarbeitung. Implementieren Sie Timeouts für lang laufende Operationen. Erwägen Sie die Verwendung von Proof-of-Work-Mechanismen, um Client- und Server-Ressourcenaufwand auszugleichen.

Häufige Auswirkungen

AuswirkungDetails
VerfügbarkeitUmfang: Verfügbarkeit

DoS: Amplifikation - Ressourcenverbrauchsangriffe, die Verfügbarkeitsauswirkungen verursachen. DoS: Ressourcenverbrauch - Übermäßige CPU, Speicher oder andere Ressourcen erschöpft.

Beispielcode

Anfälliger Code

# Anfällig: XML-Bombe (Billion-Laughs-Angriff)
import xml.etree.ElementTree as ET

def vulnerable_parse_xml(xml_string):
    # Anfällig: Keine Entity-Expansion-Limits
    tree = ET.fromstring(xml_string)
    return tree

# Angriffs-Payload (Billion Laughs):
# <?xml version="1.0"?>
# <!DOCTYPE lolz [
#   <!ENTITY lol "lol">
#   <!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
#   <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
#   ...mehr Ebenen...
# ]>
# <lolz>&lol9;</lolz>
# Dies kann zu Gigabytes an Speicher expandieren!
// Anfällig: Regex mit katastrophalem Backtracking (ReDoS)
public class VulnerableValidator {

    public boolean validateInput(String input) {
        // Anfällig: Verschachtelte Quantifizierer verursachen exponentielles Backtracking
        // Eingabe wie "aaaaaaaaaaaaaaaaaaaaaaaaaaaaX" kann Stunden dauern
        return input.matches("^(a+)+$");
    }

    public boolean validateEmail(String email) {
        // Anfällig: Komplexer Regex mit Backtracking
        String pattern = "^([a-zA-Z0-9]+\\.?)+@([a-zA-Z0-9]+\\.)+[a-zA-Z]{2,}$";
        return email.matches(pattern);
    }
}
// Anfällig: Hash-Tabelle mit vorhersagbarer Kollision
typedef struct {
    char *key;
    void *value;
    struct node *next;
} HashNode;

unsigned int vulnerable_hash(const char *key) {
    // Anfällig: Schwache Hash-Funktion
    // Angreifer kann Eingaben erzeugen, die alle auf denselben Bucket hashen
    unsigned int hash = 0;
    while (*key) {
        hash = hash * 31 + *key++;
    }
    return hash % TABLE_SIZE;
}

void vulnerable_insert(HashTable *table, const char *key, void *value) {
    // Anfällig: Mit präparierten Schlüsseln landen alle Elemente im selben Bucket
    // Lookup wird O(n) statt O(1)
    unsigned int index = vulnerable_hash(key);
    // Am Anfang der Kette einfügen...
}

Korrigierter Code

# Korrigiert: Entity-Expansion beim XML-Parsing deaktivieren
import defusedxml.ElementTree as ET  # defusedxml-Bibliothek verwenden

def secure_parse_xml(xml_string, max_size=1024*1024):  # 1MB Limit
    # Korrigiert: Größe vor Parsing prüfen
    if len(xml_string) > max_size:
        raise ValueError("XML zu groß")

    # Korrigiert: defusedxml verhindert Entity-Expansion-Angriffe
    try:
        tree = ET.fromstring(xml_string)
        return tree
    except ET.ParseError as e:
        raise ValueError(f"Ungültiges XML: {e}")

# Alternative: Standard-Parser mit Limits konfigurieren
from xml.etree.ElementTree import XMLParser

def secure_parse_xml_standard(xml_string):
    parser = XMLParser()
    # Python 3.9+ unterstützt forbid_dtd und forbid_entities
    # Für ältere Versionen defusedxml verwenden
// Korrigiert: Atomic Groups oder possessive Quantifizierer verwenden um Backtracking zu verhindern
public class SecureValidator {

    public boolean validateInput(String input) {
        // Korrigiert: Possessiver Quantifizierer verwenden (kein Backtracking)
        return input.matches("^a++$");
    }

    public boolean validateEmail(String email) {
        // Korrigiert: Einfacherer Regex ohne verschachtelte Quantifizierer
        // Auch Längenlimit hinzufügen
        if (email.length() > 254) {
            return false;
        }

        // Korrigiert: Atomic Groups oder einfacheres Muster verwenden
        String pattern = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$";
        return email.matches(pattern);
    }

    // Alternative: Timeout für Regex-Matching verwenden
    public boolean validateWithTimeout(String input, String pattern) {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<Boolean> future = executor.submit(() -> input.matches(pattern));

        try {
            return future.get(1, TimeUnit.SECONDS);  // 1 Sekunde Timeout
        } catch (TimeoutException e) {
            future.cancel(true);
            return false;  // Timeout als ungültig behandeln
        } catch (Exception e) {
            return false;
        } finally {
            executor.shutdown();
        }
    }
}
// Korrigiert: Kryptographisch starken Hash mit zufälligem Seed verwenden
#include <stdlib.h>
#include <string.h>

static uint64_t hash_seed;

void init_hash_table() {
    // Korrigiert: Mit zufälligem Seed beim Start initialisieren
    hash_seed = ((uint64_t)rand() << 32) | rand();
}

unsigned int secure_hash(const char *key) {
    // Korrigiert: SipHash oder ähnliche schlüsselbasierte Hash-Funktion
    uint64_t hash = hash_seed;
    while (*key) {
        hash = hash * 0x5bd1e995 + *key++;
        hash ^= hash >> 15;
    }
    return (unsigned int)(hash % TABLE_SIZE);
}

// Alternative: Rot-Schwarz-Baum für Worst-Case O(log n) statt Hash-Tabelle verwenden

CVE-Beispiele

  • CVE-1999-0513 — Smurf-Amplifikationsangriff mit ICMP-Echo-Anfragen an Broadcast-Adressen.
  • CVE-2003-1564 — XML-Bomben mit Entity-Expansion, die Gigabytes an Speicher verbrauchen.
  • CVE-2020-10735 — Python String-zu-Int-Konvertierung mit unerwartet hohen Ziffernzahlen verursacht CPU-Erschöpfung.
  • CVE-2013-5211 — NTP-monlist-Befehl ermöglicht Amplifikationsangriffe.
  • CVE-2002-20001 — DHE-Schlüsselvereinbarungsangriffe erzwingen teure kryptographische Berechnungen.

Referenzen

  1. MITRE Corporation. "CWE-405: Asymmetric Resource Consumption (Amplification)." https://cwe.mitre.org/data/definitions/405.html
  2. OWASP. "XML External Entity Prevention Cheat Sheet." https://cheatsheetseries.owasp.org/