Hinzufügen von Datenstruktur-Sentinel

Beschreibung

Hinzufügen von Datenstruktur-Sentinel ist eine Schwachstelle, bei der das versehentliche Hinzufügen eines Datenstruktur-Sentinels ernsthafte Programmierlogik-Probleme verursachen kann. Datenstruktur-Sentinels wie Null-Zeichen in Strings oder spezielle Marker in verketteten Listen kontrollieren die Integrität der Datenstruktur und markieren Grenzen. Wenn Benutzereingaben Sentinel-Werte in Datenstrukturen einführen können, können Angreifer Daten abschneiden, Validierung umgehen oder anderes unerwartetes Verhalten verursachen, indem sie diese Steuerzeichen einfügen.

Risiko

Unbeabsichtigtes Sentinel-Hinzufügen ermöglicht Angreifern, das Verhalten von Datenstrukturen zu manipulieren. Das Einfügen von Null-Bytes in Strings verursacht vorzeitige Terminierung, schneidet Daten ab oder umgeht Sicherheitsprüfungen, die Inhalt nach dem Null untersuchen. In Dateipfaden können Null-Bytes Pfade abschneiden, um auf unbeabsichtigte Dateien zuzugreifen. In Datenbanken kann Sentinel-Injection Datenstrukturen korrumpieren. Die hohe Wahrscheinlichkeit der Ausnutzung kombiniert mit der Fähigkeit, Sicherheitskontrollen zu umgehen, macht dies zu einer signifikanten Schwachstelle. Angreifer können Sentinel-Injection verwenden, um Eingabefilter zu umgehen oder Anwendungslogik zu manipulieren.

Lösung

Kapseln Sie Benutzer von Sentinel-Interaktion durch ordnungsgemäße Abstraktionsschichten. Validieren Sie alle Eingaben, um Sentinel-Werte auszuschließen, bevor Daten in Strukturen einbezogen werden. Implementieren Sie ordnungsgemäße Fehlerprüfung, um unbeabsichtigte Sentinel-Einfügung zu verhindern. Verwenden Sie Abstraktionsbibliotheken, die riskante APIs maskieren und Sentinels intern behandeln. Für Strings, bereinigen oder lehnen Sie Null-Bytes in Benutzereingaben ab. Erwägen Sie die Verwendung von langen-präfixierten Datenstrukturen anstelle von sentinel-terminierten. Wenden Sie OS-Level präventive Funktionalität an, wo verfügbar.

Häufige Auswirkungen

AuswirkungDetails
IntegritätUmfang: Integrität

Anwendungsdaten modifizieren - Sentinel-Hinzufügung führt generell dazu, dass Datenstrukturen nicht ordnungsgemäß funktionieren, indem Daten am eingefügten Sentinel-Punkt abgeschnitten werden.
ZugriffskontrolleUmfang: Zugriffskontrolle

Schutzmechanismus umgehen - Sicherheitsprüfungen, die Daten nach einem eingefügten Sentinel untersuchen, können umgangen werden, da sie den verbleibenden Inhalt nicht sehen.

Beispielcode

Anfälliger Code

// Anfällig: Benutzereingabe mit Null-Byte
#include <stdio.h>
#include <string.h>

void vulnerable_string_input() {
    char buffer[256];
    int c;
    int i = 0;

    // Anfällig: fgetc kann Null-Bytes lesen
    while ((c = fgetc(stdin)) != EOF && c != '\n' && i < 255) {
        buffer[i++] = c;  // Null-Byte (0x00) kann hier eingefügt werden
    }
    buffer[i] = '\0';

    // Wenn Benutzer "admin\x00ignore_this" eingibt
    // buffer enthält: "admin\0ignore_this\0"
    // strlen(buffer) gibt 5 zurück
    // strcmp(buffer, "admin") gibt 0 zurück - Übereinstimmung!
    // Aber beabsichtigte Eingabe war "admin\x00ignore_this"

    printf("Eingabe: %s\n", buffer);  // Gibt nur "admin" aus
}

// Anfällig: Pfadtraversierung via Null-Byte-Injection
void vulnerable_file_access(const char *user_filename) {
    char filepath[512];
    snprintf(filepath, sizeof(filepath), "/var/data/%s.txt", user_filename);

    // Angreifer liefert: "../../etc/passwd\x00"
    // filepath wird zu: "/var/data/../../etc/passwd\x00.txt"
    // fopen sieht: "/var/data/../../etc/passwd"
    // Die ".txt"-Erweiterung wird durch Null-Byte ignoriert

    FILE *f = fopen(filepath, "r");
    if (f) {
        // Liest /etc/passwd anstelle der beabsichtigten Datei
        char content[1024];
        fread(content, 1, sizeof(content), f);
        fclose(f);
    }
}
<?php
// Anfällig: PHP Null-Byte-Injection
function vulnerable_include($page) {
    // Beabsichtigt: nur .php Dateien aus pages-Verzeichnis einbinden
    $file = "pages/" . $page . ".php";

    // Angreifer liefert: "../../../../etc/passwd\x00"
    // $file wird zu: "pages/../../../../etc/passwd\x00.php"
    // PHP (ältere Versionen) sieht: "pages/../../../../etc/passwd"

    if (file_exists($file)) {
        include($file);  // Bindet /etc/passwd ein
    }
}

// Anfällig: Erweiterungs-Validierungs-Umgehung
function vulnerable_upload($filename, $content) {
    $allowed_extensions = array('jpg', 'png', 'gif');

    // Erweiterung extrahieren
    $ext = pathinfo($filename, PATHINFO_EXTENSION);

    // Angreifer liefert: "malware.php\x00.jpg"
    // pathinfo sieht Erweiterung als "jpg" (nach Null)
    // Aber Dateisystem kann als "malware.php" speichern

    if (in_array(strtolower($ext), $allowed_extensions)) {
        file_put_contents("uploads/" . $filename, $content);
        // Bösartige PHP-Datei hochgeladen
    }
}
?>
# Anfällig: Sentinel-Hinzufügung bei Datenverarbeitung
class VulnerableDataProcessor:
    RECORD_SEPARATOR = '\x1E'  # ASCII Record Separator

    def add_record(self, data):
        # Anfällig: Benutzer kann Record-Separator einfügen
        # Dies teilt ihre Daten in mehrere Datensätze
        self.buffer += data + self.RECORD_SEPARATOR

        # Angreifer liefert: "value1\x1Emalicious_record"
        # Erzeugt zwei Datensätze anstelle von einem

    def validate_input(self, user_input):
        # Anfällig: Validierung geschieht nach Null-Bytes
        # Angreifer: "safe_input\x00<script>alert(1)</script>"

        if "script" not in user_input.lower():
            return True  # Besteht weil Vergleich C-Strings verwendet

        # In einigen Kontexten wird Teil nach Null noch verarbeitet
        return False

    def create_command(self, user_arg):
        # Anfällig: Null-Byte schneidet Befehl ab
        command = f"process --safe-mode --input={user_arg}"

        # Angreifer: "file.txt\x00--unsafe-mode"
        # Kann bei Null abschneiden, oder durch Shell durchlassen
        # abhängig davon wie Befehl ausgeführt wird

        return command
// Anfällig: Java mit nativen Aufrufen kann betroffen sein
public class VulnerableNativeHandler {

    // Native Methode die C-Strings verwendet
    private native void processFile(String filename);

    public void handleUserFile(String userFilename) {
        // Anfällig: Java String kann Null-Bytes enthalten
        // Nativer Code der strlen/strcmp verwendet wird bei Null abschneiden

        // Benutzer liefert: "safe.txt\0../../etc/passwd"
        // Java sieht vollständigen String
        // Nativer C-Code sieht: "safe.txt"

        if (userFilename.endsWith(".txt")) {
            processFile(userFilename);
            // Nativer Code kann falsche Datei verarbeiten
        }
    }

    // Anfällig: Datenbank-Sentinel-Injection
    public void storeData(String key, String value) {
        // Wenn Datenbank spezielle Byte-Sequenzen als Trennzeichen verwendet
        // kann Angreifer sie einfügen um Speicher zu korrumpieren

        String record = key + "\t" + value;  // Tab als Separator

        // Angreifer-value: "data\tanother_key\tattacker_value"
        // Erzeugt mehrere Datensätze anstelle von einem

        database.write(record);
    }
}

Korrigierter Code

// Korrigiert: Null-Bytes in Benutzereingabe ablehnen
#include <stdio.h>
#include <string.h>

int secure_string_input(char *buffer, size_t buffer_size) {
    int c;
    size_t i = 0;

    while ((c = fgetc(stdin)) != EOF && c != '\n' && i < buffer_size - 1) {
        // Korrigiert: Null-Bytes ablehnen
        if (c == '\0') {
            fprintf(stderr, "Fehler: Null-Byte in Eingabe nicht erlaubt\n");
            buffer[0] = '\0';
            return -1;
        }
        buffer[i++] = c;
    }
    buffer[i] = '\0';

    return 0;
}

// Korrigiert: Pfadkomponenten ohne Null-Bytes validieren
int secure_file_access(const char *user_filename) {
    // Korrigiert: Auf Null-Bytes in Eingabe prüfen
    if (memchr(user_filename, '\0', strlen(user_filename) + 1) !=
        user_filename + strlen(user_filename)) {
        // Diese Prüfung erkennt ob eingebettete Nulls vorhanden sind
        // Tatsächlich stoppt strlen beim ersten Null, also anderen Ansatz verwenden
    }

    // Korrigiert: Besserer Ansatz - Zeichen für Zeichen validieren
    for (size_t i = 0; user_filename[i] != '\0'; i++) {
        // Korrigiert: Null-Bytes und Pfadtraversierung ablehnen
        if (user_filename[i] == '\0' ||
            user_filename[i] == '/' ||
            user_filename[i] == '\\') {
            return -1;
        }
    }

    // Korrigiert: Sichere Pfadkonstruktion verwenden
    char filepath[512];
    int written = snprintf(filepath, sizeof(filepath),
                           "/var/data/%s.txt", user_filename);

    if (written < 0 || written >= sizeof(filepath)) {
        return -1;  // Pfad zu lang oder Fehler
    }

    // Korrigiert: Verifizieren dass keine Pfadtraversierung aufgetreten ist
    char resolved[PATH_MAX];
    if (realpath(filepath, resolved) == NULL) {
        return -1;
    }

    if (strncmp(resolved, "/var/data/", 10) != 0) {
        return -1;  // Beabsichtigtes Verzeichnis verlassen
    }

    FILE *f = fopen(resolved, "r");
    // ...
    return 0;
}
<?php
// Korrigiert: Null-Byte-Bereinigung
function secure_include($page) {
    // Korrigiert: Null-Bytes entfernen
    $page = str_replace(chr(0), '', $page);

    // Korrigiert: Erlaubte Seiten als Whitelist
    $allowed_pages = array('home', 'about', 'contact', 'products');

    if (!in_array($page, $allowed_pages)) {
        die('Ungültige Seite');
    }

    $file = "pages/" . $page . ".php";
    include($file);
}

// Korrigiert: Sicherer Datei-Upload
function secure_upload($filename, $content) {
    // Korrigiert: Null-Bytes aus Dateinamen entfernen
    $filename = str_replace(chr(0), '', $filename);

    // Korrigiert: Sicheren Dateinamen generieren
    $safe_name = preg_replace('/[^a-zA-Z0-9_.-]/', '', $filename);

    // Korrigiert: Erweiterung anhand des tatsächlichen Dateiinhalts verifizieren
    $finfo = new finfo(FILEINFO_MIME_TYPE);
    $mime = $finfo->buffer($content);

    $allowed_mimes = array(
        'image/jpeg' => 'jpg',
        'image/png' => 'png',
        'image/gif' => 'gif'
    );

    if (!isset($allowed_mimes[$mime])) {
        die('Ungültiger Dateityp');
    }

    // Korrigiert: Erkannte Erweiterung verwenden
    $safe_filename = pathinfo($safe_name, PATHINFO_FILENAME) . '.' . $allowed_mimes[$mime];

    file_put_contents("uploads/" . $safe_filename, $content);
}
?>
# Korrigiert: Sentinel-Bereinigung bei Datenverarbeitung
class SecureDataProcessor:
    RECORD_SEPARATOR = '\x1E'
    FORBIDDEN_BYTES = ['\x00', '\x1E', '\x1F']  # Null und Record-Separatoren

    def sanitize_input(self, data):
        """Sentinel-Zeichen aus Eingabe entfernen oder escapen."""
        sanitized = data
        for byte in self.FORBIDDEN_BYTES:
            sanitized = sanitized.replace(byte, '')
        return sanitized

    def add_record(self, data):
        # Korrigiert: Vor Hinzufügen bereinigen
        clean_data = self.sanitize_input(data)
        self.buffer += clean_data + self.RECORD_SEPARATOR

    def validate_input(self, user_input):
        # Korrigiert: Zuerst auf Null-Bytes prüfen
        if '\x00' in user_input:
            raise ValueError("Null-Bytes in Eingabe nicht erlaubt")

        # Korrigiert: Jetzt sicher Inhalt zu prüfen
        if "script" in user_input.lower():
            return False
        return True

    def create_command(self, user_arg):
        # Korrigiert: Null-Bytes ablehnen
        if '\x00' in user_arg:
            raise ValueError("Null-Bytes nicht erlaubt")

        # Korrigiert: Parametrisierte Ausführung verwenden
        import subprocess
        return subprocess.run(
            ['process', '--safe-mode', f'--input={user_arg}'],
            capture_output=True
        )
// Korrigiert: Null-Byte-Behandlung in Java
public class SecureNativeHandler {

    private native void processFile(String filename);

    public void handleUserFile(String userFilename) throws SecurityException {
        // Korrigiert: Auf Null-Bytes prüfen
        if (userFilename.indexOf('\0') != -1) {
            throw new SecurityException("Null-Bytes in Dateinamen nicht erlaubt");
        }

        // Korrigiert: Dateinamen-Zeichen validieren
        if (!userFilename.matches("^[a-zA-Z0-9_.-]+\\.txt$")) {
            throw new SecurityException("Ungültiges Dateinamen-Format");
        }

        // Korrigiert: Pfad auflösen und verifizieren dass er im erlaubten Verzeichnis ist
        Path basePath = Paths.get("/var/data").toRealPath();
        Path filePath = basePath.resolve(userFilename).normalize();

        if (!filePath.startsWith(basePath)) {
            throw new SecurityException("Pfadtraversierung erkannt");
        }

        processFile(filePath.toString());
    }

    // Korrigiert: Ordnungsgemäße Kodierung für Datenbankspeicherung
    public void storeData(String key, String value) throws SecurityException {
        // Korrigiert: Validieren dass keine Steuerzeichen
        if (containsControlChars(key) || containsControlChars(value)) {
            throw new SecurityException("Steuerzeichen nicht erlaubt");
        }

        // Korrigiert: Ordnungsgemäßes Escaping oder parametrisierte Speicherung verwenden
        PreparedStatement stmt = connection.prepareStatement(
            "INSERT INTO data (key, value) VALUES (?, ?)"
        );
        stmt.setString(1, key);
        stmt.setString(2, value);
        stmt.executeUpdate();
    }

    private boolean containsControlChars(String s) {
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (c < 32 && c != '\t' && c != '\n' && c != '\r') {
                return true;
            }
        }
        return false;
    }
}

CVE-Beispiele

Keine spezifischen CVEs sind in der MITRE-Datenbank für dieses CWE aufgeführt. Das Muster ist jedoch stark dokumentiert in:

  • Null-Byte-Injection-Angriffen (PHP File-Inclusion, Pfadtraversierung)
  • CERT C: STR03-C. Do not inadvertently truncate a string
  • CERT C: STR06-C. Do not assume that strtok() leaves the parse string unchanged

Referenzen

  1. MITRE Corporation. "CWE-464: Addition of Data Structure Sentinel." https://cwe.mitre.org/data/definitions/464.html
  2. CERT C Secure Coding Standard. "STR03-C. Do not inadvertently truncate a string."
  3. OWASP. "Embedding Null Code." https://owasp.org/www-community/attacks/Embedding_Null_Code