Nur Filterung von Sonderzeichen relativ zu einer Markierung

Beschreibung

Nur Filterung von Sonderzeichen relativ zu einer Markierung ist eine Schwachstelle bei der Eingabevalidierung, bei der Software gefährliche Elemente nur filtert, wenn sie an bestimmten Positionen relativ zu String-Markierungen erscheinen, wie dem Anfang (^) oder Ende ($) eines Strings. Dieser Ansatz verwendet verankertes Muster-Matching, das nur an Grenzpositionen prüft, wodurch identische gefährliche Sequenzen durchgelassen werden, wenn sie anderswo in der Eingabe erscheinen. Der Filter nimmt an, dass Angreifer bösartigen Inhalt an vorhersehbaren Stellen platzieren werden, was leicht zu umgehen ist.

Risiko

Angreifer können markierungsrelative Filterung trivial umgehen, indem sie gefährliche Sequenzen weg von der geprüften Markierung positionieren. Wenn ein Filter "../" nur am String-Anfang entfernt, passieren Eingaben wie "x/../../../etc/passwd" oder "foo/../../../etc/passwd" völlig unverändert. Dies ist besonders gefährlich bei der Pfadbehandlung, wo jede Traversal-Sequenz, unabhängig von der Position, den Verzeichnisbaum navigieren kann. Die Schwachstelle ist häufig, wenn Entwickler Regex-Anker (^, $) verwenden, ohne zu realisieren, dass sie das Matching auf bestimmte Positionen beschränken. Selbst eine einzelne ungefilterte Instanz einer gefährlichen Sequenz kann die beabsichtigte Sicherheitskontrolle vollständig kompromittieren.

Lösung

Entfernen Sie Positionsanker aus sicherheitskritischem Muster-Matching, es sei denn, der gesamte String muss einem bestimmten Format entsprechen. Verwenden Sie globale, unverankterte Muster, die gefährliche Sequenzen überall in der Eingabe finden. Für Pfadvalidierung lösen Sie Eingaben zu kanonischen Pfaden auf und überprüfen Sie, ob sie innerhalb erlaubter Verzeichnisse verbleiben. Implementieren Sie iterative Filterung, die fortgesetzt wird, bis keine gefährlichen Muster mehr gefunden werden. Bevorzugen Sie Allowlist-Validierung, die nur bekannt sichere Zeichen akzeptiert. Wenn Anker für Formatvalidierung benötigt werden, kombinieren Sie sie mit umfassender Inhaltsvalidierung, die die gesamte Eingabe untersucht.

Häufige Auswirkungen

AuswirkungDetails
IntegritätBereich: Integrität

Unerwarteter Zustand - Gefährliche Elemente, die weg von Markierungen positioniert sind, passieren Filter unverändert.
VertraulichkeitBereich: Vertraulichkeit

Anwendungsdaten lesen - Ungefilterte Path-Traversal-Sequenzen ermöglichen Zugriff auf sensible Dateien.
IntegritätBereich: Integrität

Unautorisierten Code ausführen - Injection-Sequenzen vermeiden Filterung, indem sie nach geprüften Markierungen erscheinen.

Beispielcode

Verwundbarer Code

# Verwundbar: ^ Anker matched nur am String-Anfang
my $Username = GetUntrustedInput();

# Verwundbar: Entfernt nur "../" ganz am Anfang
$Username =~ s/^\.\.\///;

my $filename = "/home/user/" . $Username;
ReadAndSendFile($filename);

# Angriff: "../../../etc/passwd" -> entfernt erstes, lässt "../../etc/passwd"
# Angriff: "x/../../../etc/passwd" -> "../" nicht am Anfang, unverändert
# Angriff: "subdir/../../../etc/passwd" -> Präfix ermöglicht Bypass
# Verwundbar: Prüft nur ob String mit gefährlichem Muster beginnt
def vulnerable_filter(path):
    # Verwundbar: Entfernt nur führende Traversal
    if path.startswith('../'):
        path = path[3:]
    return path

# Angriff: "foo/../../../etc/passwd" - beginnt nicht mit "../"
# Angriff: "./../../etc/passwd" - beginnt mit "./" nicht "../"

Lösungscode

# Behoben: Anker entfernen, globales Matching mit Schleife verwenden
my $Username = GetUntrustedInput();

# Behoben: Kein ^-Anker - matched überall
# Schleife behandelt verschachtelte Muster
my $prev;
do {
    $prev = $Username;
    $Username =~ s/\.\.[\\/]//g;  # Beide Trennzeichen matchen
} while ($Username ne $prev);

# Besser: Allowlist-Validierung
unless ($Username =~ /^[a-zA-Z0-9_.-]+$/) {
    die "Ungültiger Benutzername";
}

my $filename = "/home/user/" . $Username;
# Behoben: Gesamten String prüfen, kanonischen Pfad verwenden
import os.path

def fixed_filter(path):
    # Behoben: Von überall entfernen, Schleife bis stabil
    prev = None
    while path != prev:
        prev = path
        path = path.replace('../', '').replace('..\\', '')
    return path

# Besser: Kanonische Pfadvalidierung
def fixed_validate_path(base_dir, user_path):
    # Zu kanonischer Form auflösen
    full_path = os.path.realpath(os.path.join(base_dir, user_path))
    base_path = os.path.realpath(base_dir)

    # Verifizieren, dass Ergebnis unter Basisverzeichnis ist
    if not full_path.startswith(base_path + os.sep):
        raise ValueError("Path-Traversal erkannt")
    return full_path

Verwandte CWEs

  • CWE-795: Nur Filterung von Sonderzeichen an einer bestimmten Position (Eltern)
  • CWE-797: Nur Filterung von Sonderzeichen an einer absoluten Position (Geschwister)
  • CWE-791: Unvollständige Filterung von Sonderzeichen (Großeltern)
  • CWE-22: Unsachgemäße Einschränkung eines Pfadnamens auf ein beschränktes Verzeichnis (verwandte Ausnutzung)

Referenzen

  1. MITRE Corporation. "CWE-796: Only Filtering Special Elements Relative to a Marker." https://cwe.mitre.org/data/definitions/796.html
  2. OWASP. "Path Traversal." https://owasp.org/www-community/attacks/Path_Traversal
  3. Regular-Expressions.info. "Anchors." https://www.regular-expressions.info/anchors.html