Ausführbarer Regulärer-Ausdruck-Fehler

Beschreibung

Ausführbarer Regulärer-Ausdruck-Fehler tritt auf, wenn Anwendungen Regex-Engines verwenden, die ausführbaren Code innerhalb von Mustern erlauben. Einige Regex-Implementierungen (wie Perls /e-Modifikator oder Rubys gsub mit Evaluation) können beliebigen Code während des Musterabgleichs oder der Substitution ausführen. Wenn Benutzereingaben diese Regex-Operationen beeinflussen, können Angreifer bösartigen Code injizieren und ausführen.

Risiko

Angreifer können beliebigen Code auf dem Server durch manipulierte Regex-Muster oder Ersetzungsstrings ausführen. Dies führt zu vollständiger Systemkompromittierung, Datendiebstahl und lateraler Bewegung. Die Schwachstelle ist besonders gefährlich, weil Regex-Muster oft als potenzielle Code-Injection-Vektoren übersehen werden. Die Angriffsfläche umfasst sowohl Musterkonstruktion als auch Ersetzungsstring-Behandlung.

Lösung

Vermeiden Sie Regex-Engines mit Code-Ausführungsfunktionen bei der Verarbeitung von Benutzereingaben. Deaktivieren Sie Evaluationsmodifikatoren (/e in Perl, Verwendung von \e in der Ersetzung). Verwenden Sie nicht-evaluierende Substitutionsmethoden. Escapen Sie Benutzereingaben vor dem Einbeziehen in Regex. Erwägen Sie die Verwendung einfacherer String-Operationen anstelle von Regex. Implementieren Sie strikte Eingabevalidierung vor der Regex-Verarbeitung.

Häufige Auswirkungen

AuswirkungDetails
IntegritätBereich: Code-Ausführung

Beliebiger Code läuft mit Anwendungsprivilegien.
VertraulichkeitBereich: Datendiebstahl

Angreifer können auf alle Anwendungsdaten zugreifen.
VerfügbarkeitBereich: Systemkompromittierung

Vollständige Kontrolle über das System.

Beispielcode + Lösungscode

Verwundbarer Code

#!/usr/bin/perl
# VERWUNDBAR: Perl-Regex mit /e-Modifikator

# Benutzereingabe in Ersetzung mit Evaluation verwendet
sub transform_vulnerable {
    my ($text, $pattern, $replacement) = @_;

    # Der /e-Modifikator evaluiert $replacement als Code!
    $text =~ s/$pattern/$replacement/ee;

    return $text;
}

# Angriff: $replacement = 'system("rm -rf /")'
my $user_text = "Hello World";
my $user_pattern = "World";
my $user_replacement = $ARGV[0];  # Angreifer-kontrolliert!

# Wenn user_replacement ist: system('cat /etc/passwd')
# Führt es den system-Befehl aus!
my $result = transform_vulnerable($user_text, $user_pattern, $user_replacement);

# VERWUNDBAR: Doppelte Evaluation
sub process_vulnerable {
    my $input = shift;
    my $template = shift;

    # Doppeltes /e erlaubt komplexe Angriffe
    $input =~ s/\{\{(\w+)\}\}/$template->{$1}/eeg;
}

# VERWUNDBAR: Muster selbst ist benutzerkontrolliert
sub search_vulnerable {
    my ($haystack, $user_pattern) = @_;

    # Benutzer kontrolliert Regex-Muster
    # Angriff: (?{system('whoami')})
    if ($haystack =~ /$user_pattern/) {
        return 1;
    }
    return 0;
}
# VERWUNDBAR: Ruby gsub mit Block-Evaluation
def transform_vulnerable(text, pattern, replacement)
  # Wenn replacement benutzerkontrolliert und evaluiert
  text.gsub(/#{pattern}/) { eval(replacement) }
end

# VERWUNDBAR: String-Interpolation in Ersetzung
def replace_vulnerable(text, user_input)
  # Benutzereingabe in Ersetzungsstring
  text.gsub(/pattern/, "#{eval(user_input)}")
end

# VERWUNDBAR: Dynamischer Regex mit Benutzereingabe
def match_vulnerable(text, user_pattern)
  # Benutzer kontrolliert Regex - Code-Injection möglich
  regex = Regexp.new(user_pattern)
  text.match(regex)
end
<?php
// VERWUNDBAR: preg_replace mit /e-Modifikator (veraltet in PHP 5.5, entfernt in PHP 7)
function transformVulnerable($text, $pattern, $replacement) {
    // Der /e-Modifikator evaluiert Ersetzung als PHP-Code!
    return preg_replace("/$pattern/e", $replacement, $text);
}

// Angriffbeispiel:
// $pattern = ".*"
// $replacement = "system('id')"

// VERWUNDBAR: preg_replace_callback unsicher verwenden
function processVulnerable($text, $user_code) {
    return preg_replace_callback(
        '/\{\{(\w+)\}\}/',
        function($matches) use ($user_code) {
            // Evaluiert Benutzercode!
            return eval("return $user_code;");
        },
        $text
    );
}

// VERWUNDBAR: create_function (veraltet, entfernt in PHP 8)
function filterVulnerable($array, $user_condition) {
    $func = create_function('$x', "return $user_condition;");
    return array_filter($array, $func);
}
?>

Lösungscode

#!/usr/bin/perl
use strict;
use warnings;

# SICHER: Kein /e-Modifikator - einfache String-Ersetzung
sub transform_safe {
    my ($text, $pattern, $replacement) = @_;

    # Spezielle Regex-Zeichen in Benutzereingabe escapen
    $pattern = quotemeta($pattern);
    $replacement = quotemeta($replacement);

    # Kein /e-Modifikator - literale Ersetzung
    $text =~ s/$pattern/$replacement/g;

    return $text;
}

# SICHER: Hash-Lookup statt eval verwenden
sub process_safe {
    my ($input, $variables) = @_;

    $input =~ s/\{\{(\w+)\}\}/$variables->{$1} \/\/ ''/g;

    return $input;
}

# SICHER: Erlaubte Muster mit Whitelist
sub search_safe {
    my ($haystack, $user_pattern) = @_;

    # Nur alphanumerische Muster erlauben
    unless ($user_pattern =~ /^[\w\s]+$/) {
        die "Ungültiges Muster";
    }

    # Für literalen Abgleich escapen
    my $safe_pattern = quotemeta($user_pattern);

    if ($haystack =~ /$safe_pattern/) {
        return 1;
    }
    return 0;
}

# SICHER: index() statt Regex für einfache Suchen verwenden
sub find_safe {
    my ($haystack, $needle) = @_;
    return index($haystack, $needle) != -1;
}
# SICHER: Keine Evaluation in Ersetzung
def transform_safe(text, pattern, replacement)
  # Muster für literalen Abgleich escapen
  safe_pattern = Regexp.escape(pattern)

  # Literale Ersetzung, keine Evaluation
  text.gsub(/#{safe_pattern}/, replacement)
end

# SICHER: Hash-Substitution verwenden
def template_safe(text, variables)
  text.gsub(/\{\{(\w+)\}\}/) do |match|
    key = $1
    # Lookup in Hash, kein eval
    variables[key] || ''
  end
end

# SICHER: Muster validieren und einschränken
def match_safe(text, user_pattern)
  # Sichere Zeichen mit Whitelist
  unless user_pattern.match?(/^[\w\s.*?+]+$/)
    raise "Ungültige Musterzeichen"
  end

  # Musterkomplexität begrenzen
  if user_pattern.length > 100
    raise "Muster zu lang"
  end

  # Timeout für Regex-Ausführung verwenden
  Timeout.timeout(1) do
    text.match(Regexp.new(user_pattern))
  end
rescue Timeout::Error
  raise "Muster dauerte zu lange"
end

# SICHER: Einfache String-Methoden wenn möglich verwenden
def find_safe(text, search)
  text.include?(search)
end
<?php
// SICHER: preg_replace_callback mit sicherer Behandlung verwenden
function transformSafe($text, $pattern, $variables) {
    // Benutzermuster escapen
    $safePattern = preg_quote($pattern, '/');

    return preg_replace_callback(
        "/$safePattern/",
        function($matches) use ($variables) {
            // Lookup, niemals eval
            return $variables[$matches[0]] ?? $matches[0];
        },
        $text
    );
}

// SICHER: Template mit explizitem Variablen-Lookup
function templateSafe($text, array $variables) {
    return preg_replace_callback(
        '/\{\{(\w+)\}\}/',
        function($matches) use ($variables) {
            $key = $matches[1];
            // Nur Lookup von vordefinierten Variablen
            return array_key_exists($key, $variables)
                   ? htmlspecialchars($variables[$key])
                   : '';
        },
        $text
    );
}

// SICHER: Regex-Muster vor Verwendung validieren
function searchSafe($text, $userPattern) {
    // Erlaubte Zeichen mit Whitelist
    if (!preg_match('/^[\w\s.*?+\[\]()]+$/', $userPattern)) {
        throw new InvalidArgumentException('Ungültiges Muster');
    }

    // Länge begrenzen
    if (strlen($userPattern) > 100) {
        throw new InvalidArgumentException('Muster zu lang');
    }

    // Spezielle Regex-Zeichen escapen bei literaler Suche
    $safePattern = preg_quote($userPattern, '/');

    return preg_match("/$safePattern/", $text);
}

// SICHER: str_replace für einfache Fälle verwenden
function replaceSafe($text, $search, $replace) {
    return str_replace($search, $replace, $text);
}

// SICHER: Modernes PHP - anonyme Funktionen statt create_function
function filterSafe($array, callable $predicate) {
    return array_filter($array, $predicate);
}

// Verwendung
$filtered = filterSafe([1, 2, 3, 4], fn($x) => $x > 2);
?>

Ausgenutzt in der Praxis

Server-Kompromittierung

Perl-Webanwendungen mit /e-Modifikator für RCE ausgenutzt.

CMS-Schwachstellen

Content-Management-Systeme mit Regex-Verarbeitung kompromittiert.

Template-Injection

Template-Engines mit Regex-Evaluation kompromittiert.


Tools zum Testen/Ausnutzen

  • Burp Suite — Regex-Injection testen.
  • Benutzerdefinierte Skripte zum Testen der Regex-Evaluation.
  • Statische Analysatoren, die /e-Modifikator-Verwendung erkennen.

CVE-Beispiele

  • CVEs von Perl-Anwendungen mit /e-Modifikator.
  • PHP-Anwendungen mit preg_replace und /e.

Referenzen

  1. MITRE. "CWE-624: Executable Regular Expression Error." https://cwe.mitre.org/data/definitions/624.html
  2. Perl-Sicherheitsdokumentation zu /e-Modifikator-Gefahren.