Nicht in Anführungszeichen gesetzter Suchpfad oder Element

Beschreibung

Nicht in Anführungszeichen gesetzter Suchpfad oder Element tritt auf, wenn Software einen Suchpfad verwendet, der ein Element ohne Anführungszeichen enthält, und dieses Element Leerzeichen oder andere Trennzeichen enthält. Auf Windows-Systemen manifestiert sich dies häufig, wenn Dienst-Executables oder geplante Aufgaben mit Pfaden konfiguriert sind, die Leerzeichen enthalten, aber nicht ordnungsgemäß in Anführungszeichen gesetzt sind. Angreifer können dies ausnutzen, indem sie bösartige ausführbare Dateien an Orten platzieren, die dem abgeschnittenen Pfad entsprechen, wodurch diese mit erhöhten Privilegien ausgeführt werden.

Risiko

Nicht in Anführungszeichen gesetzte Dienstpfade sind ein häufiger Windows-Privilegieneskalationsvektor. Wenn ein Pfad wie "C:\Program Files\My App\service.exe" nicht in Anführungszeichen gesetzt ist, versucht Windows "C:\Program.exe" auszuführen, dann "C:\Program Files\My.exe", bevor es die korrekte ausführbare Datei findet. Wenn Angreifer nach C:\ oder C:\Program Files\ schreiben können, können sie eine bösartige ausführbare Datei platzieren, die mit den Privilegien des Dienstes (oft SYSTEM) läuft. Diese Schwachstelle betrifft Tausende von Drittanbieteranwendungen und wird häufig bei Penetrationstests gefunden.

Lösung

Setzen Sie Pfade mit Leerzeichen in Dienstkonfigurationen, geplanten Aufgaben und Registry-Einträgen immer in Anführungszeichen. Verwenden Sie den vollständigen Pfad in Anführungszeichen: "C:\Program Files\My App\service.exe". Prüfen Sie bestehende Dienste auf Pfade ohne Anführungszeichen mit Tools wie PowerUp oder manueller Registry-Inspektion. Entfernen Sie Schreibrechte von Verzeichnissen in der Windows-Pfadhierarchie. Installieren Sie Anwendungen wenn möglich in Pfaden ohne Leerzeichen. Implementieren Sie ordnungsgemäße Zugriffskontrollen auf Systemverzeichnisse.

Häufige Auswirkungen

AuswirkungDetails
ZugriffskontrolleUmfang: Privilegieneskalation

Angreifer können Code mit erhöhten Privilegien (oft SYSTEM) ausführen.
IntegritätUmfang: Systemkompromittierung

Bösartiger Code läuft anstelle legitimer Dienst-Executables.
VerfügbarkeitUmfang: Dienststörung

Legitime Dienste starten nicht, wenn sie gekapert werden.

Beispielcode

Anfällige Konfiguration

# ANFÄLLIG: Nicht in Anführungszeichen gesetzter Dienstpfad in Windows
# Dienst konfiguriert mit:
# ImagePath = C:\Program Files\My Application\service.exe

# Windows versucht diese Pfade der Reihe nach:
# 1. C:\Program.exe
# 2. C:\Program Files\My.exe
# 3. C:\Program Files\My Application\service.exe

# Auf anfällige Dienste prüfen
Get-WmiObject win32_service | Where-Object {
    $_.PathName -like '* *' -and
    $_.PathName -notlike '"*"' -and
    $_.PathName -notlike '* -*'
} | Select-Object Name, PathName, StartMode, State

# ANFÄLLIG: Geplante Aufgabe mit Pfad ohne Anführungszeichen
schtasks /create /tn "MyTask" /tr C:\Program Files\App\task.exe /sc daily /st 09:00

# ANFÄLLIG: Registry-Eintrag
# HKLM\SYSTEM\CurrentControlSet\Services\MyService
# ImagePath: C:\Program Files\Vulnerable App\svc.exe
// ANFÄLLIG: C/C++ CreateProcess ohne Anführungszeichen
#include <windows.h>

void StartServiceVulnerable() {
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi;

    // Pfad ohne Anführungszeichen - anfällig!
    CreateProcess(
        NULL,
        "C:\\Program Files\\My App\\service.exe",  // Ohne Anführungszeichen!
        NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi
    );
}

// ANFÄLLIG: ShellExecute mit Pfad ohne Anführungszeichen
void LaunchAppVulnerable() {
    ShellExecute(
        NULL,
        "open",
        "C:\\Program Files\\My App\\launcher.exe",  // Ohne Anführungszeichen!
        NULL, NULL, SW_SHOW
    );
}
// ANFÄLLIG: C# Service-Installer ohne Anführungszeichen
using System.ServiceProcess;

public class VulnerableServiceInstaller : Installer
{
    public VulnerableServiceInstaller()
    {
        var processInstaller = new ServiceProcessInstaller();
        var serviceInstaller = new ServiceInstaller();

        // Pfad ohne Anführungszeichen!
        serviceInstaller.ServiceName = "MyService";
        // In Registry gesetzter Pfad wird ohne Anführungszeichen sein
    }
}

// ANFÄLLIG: Process.Start mit Pfad ohne Anführungszeichen
public void LaunchVulnerable()
{
    // Wenn Pfad Leerzeichen hat und nicht in Anführungszeichen ist...
    Process.Start("C:\\Program Files\\My App\\app.exe");
}

Ausnutzungsbeispiel

# Angreifer-Ausnutzungsschritte:

# 1. Anfällige Dienste finden
$services = Get-WmiObject win32_service | Where-Object {
    $_.PathName -match '^[^"].*\s.*[^"]

### Korrigierte Konfiguration

```powershell
# SICHER: Ordnungsgemäß in Anführungszeichen gesetzter Dienstpfad
# ImagePath = "C:\Program Files\My Application\service.exe"

# Bestehende Dienste via Registry reparieren
$servicePath = 'HKLM:\SYSTEM\CurrentControlSet\Services\MyService'
$currentPath = (Get-ItemProperty $servicePath).ImagePath

if ($currentPath -notlike '"*"') {
    $quotedPath = '"' + $currentPath + '"'
    Set-ItemProperty -Path $servicePath -Name ImagePath -Value $quotedPath
}

# SICHER: Geplante Aufgabe mit Pfad in Anführungszeichen erstellen
schtasks /create /tn "MyTask" /tr '"C:\Program Files\App\task.exe"' /sc daily /st 09:00

# PowerShell-Skript um alle Pfade ohne Anführungszeichen zu reparieren
$services = Get-WmiObject win32_service | Where-Object {
    $_.PathName -like '* *' -and
    $_.PathName -notlike '"*"'
}

foreach ($service in $services) {
    $name = $service.Name
    $path = $service.PathName

    # Executable-Pfad extrahieren (Argumente behandeln)
    if ($path -match '^(.+\.exe)') {
        $exePath = $matches[1]
        $args = $path.Substring($exePath.Length)
        $fixedPath = '"' + $exePath + '"' + $args

        Write-Host "Repariere: $name"
        Write-Host "  Alt: $path"
        Write-Host "  Neu: $fixedPath"

        # Registry aktualisieren
        $regPath = "HKLM:\SYSTEM\CurrentControlSet\Services\$name"
        Set-ItemProperty -Path $regPath -Name ImagePath -Value $fixedPath
    }
}
// SICHER: C/C++ CreateProcess mit Pfad in Anführungszeichen
#include <windows.h>

void StartServiceSafe() {
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi;

    // Ordnungsgemäß in Anführungszeichen gesetzter Pfad
    CreateProcess(
        NULL,
        "\"C:\\Program Files\\My App\\service.exe\"",  // In Anführungszeichen!
        NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi
    );
}

// SICHER: lpApplicationName-Parameter verwenden
void StartServiceSafer() {
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi;

    // lpApplicationName verwenden vermeidet Pfad-Parsing-Probleme
    CreateProcess(
        "C:\\Program Files\\My App\\service.exe",  // Vollständiger Pfad hier
        NULL,  // Oder Befehlszeile mit Argumenten
        NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi
    );
}

// SICHER: Hilfsfunktion für Anführungszeichen bei Pfaden
char* QuotePath(const char* path) {
    if (path == NULL) return NULL;

    // Prüfen ob bereits in Anführungszeichen
    if (path[0] == '"') return strdup(path);

    // Prüfen ob Anführungszeichen benötigt (enthält Leerzeichen)
    if (strchr(path, ' ') == NULL) return strdup(path);

    // Anführungszeichen hinzufügen
    size_t len = strlen(path) + 3;  // 2 Anführungszeichen + null
    char* quoted = malloc(len);
    snprintf(quoted, len, "\"%s\"", path);
    return quoted;
}
// SICHER: C# Service-Installer mit Pfad in Anführungszeichen
using System.ServiceProcess;
using System.Configuration.Install;
using Microsoft.Win32;

[RunInstaller(true)]
public class SafeServiceInstaller : Installer
{
    public SafeServiceInstaller()
    {
        var processInstaller = new ServiceProcessInstaller
        {
            Account = ServiceAccount.LocalSystem
        };

        var serviceInstaller = new ServiceInstaller
        {
            ServiceName = "MyService",
            DisplayName = "My Service",
            StartType = ServiceStartMode.Automatic
        };

        Installers.Add(processInstaller);
        Installers.Add(serviceInstaller);
    }

    public override void Install(IDictionary stateSaver)
    {
        base.Install(stateSaver);

        // Sicherstellen, dass Pfad in Registry in Anführungszeichen ist
        using (var key = Registry.LocalMachine.OpenSubKey(
            @"SYSTEM\CurrentControlSet\Services\MyService", true))
        {
            if (key != null)
            {
                var imagePath = key.GetValue("ImagePath") as string;
                if (!string.IsNullOrEmpty(imagePath) && !imagePath.StartsWith("\""))
                {
                    // Pfad in Anführungszeichen setzen
                    key.SetValue("ImagePath", $"\"{imagePath}\"");
                }
            }
        }
    }
}

// SICHER: Process.Start mit ordnungsgemäßen Anführungszeichen
public void LaunchSafe(string path)
{
    var startInfo = new ProcessStartInfo
    {
        FileName = path,  // .NET behandelt Anführungszeichen intern
        UseShellExecute = false
    };

    Process.Start(startInfo);
}

// SICHER: Hilfsfunktion um Anführungszeichen bei Pfaden sicherzustellen
public static string EnsureQuotedPath(string path)
{
    if (string.IsNullOrEmpty(path)) return path;

    // Bereits in Anführungszeichen
    if (path.StartsWith("\"") && path.EndsWith("\"")) return path;

    // Benötigt Anführungszeichen (enthält Leerzeichen)
    if (path.Contains(" "))
    {
        return $"\"{path}\"";
    }

    return path;
}
# Erkennungs- und Behebungsskript
import winreg
import re

def find_unquoted_service_paths():
    """Dienste mit Pfaden ohne Anführungszeichen finden, die Leerzeichen enthalten."""
    vulnerable = []

    services_key = r"SYSTEM\CurrentControlSet\Services"

    try:
        with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, services_key) as key:
            i = 0
            while True:
                try:
                    service_name = winreg.EnumKey(key, i)
                    service_path = f"{services_key}\\{service_name}"

                    with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, service_path) as svc_key:
                        try:
                            image_path, _ = winreg.QueryValueEx(svc_key, "ImagePath")

                            # Prüfen ob ohne Anführungszeichen und Leerzeichen enthält
                            if ' ' in image_path and not image_path.startswith('"'):
                                # Executable-Pfad extrahieren
                                exe_match = re.match(r'^(.+\.exe)', image_path, re.IGNORECASE)
                                if exe_match:
                                    exe_path = exe_match.group(1)
                                    if ' ' in exe_path:
                                        vulnerable.append({
                                            'name': service_name,
                                            'path': image_path
                                        })
                        except FileNotFoundError:
                            pass

                    i += 1
                except OSError:
                    break

    except Exception as e:
        print(f"Fehler: {e}")

    return vulnerable

def fix_unquoted_path(service_name):
    """Pfad ohne Anführungszeichen für Dienst reparieren."""
    service_path = f"SYSTEM\\CurrentControlSet\\Services\\{service_name}"

    try:
        with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, service_path,
                           0, winreg.KEY_READ | winreg.KEY_WRITE) as key:
            image_path, _ = winreg.QueryValueEx(key, "ImagePath")

            if not image_path.startswith('"'):
                # Executable und Argumente finden
                exe_match = re.match(r'^(.+\.exe)(.*)', image_path, re.IGNORECASE)
                if exe_match:
                    exe_path = exe_match.group(1)
                    args = exe_match.group(2)
                    fixed_path = f'"{exe_path}"{args}'

                    winreg.SetValueEx(key, "ImagePath", 0, winreg.REG_EXPAND_SZ, fixed_path)
                    print(f"Repariert: {service_name}")
                    print(f"  Alt: {image_path}")
                    print(f"  Neu: {fixed_path}")
                    return True

    except Exception as e:
        print(f"Fehler beim Reparieren von {service_name}: {e}")

    return False

# Erkennung ausführen
if __name__ == "__main__":
    print("Scanne nach Dienstpfaden ohne Anführungszeichen...\n")
    vulnerable = find_unquoted_service_paths()

    for svc in vulnerable:
        print(f"[ANFÄLLIG] {svc['name']}")
        print(f"  Pfad: {svc['path']}\n")

    print(f"\n{len(vulnerable)} anfällige Dienste gefunden")

Ausgenutzt in der Praxis

Häufiger Penetrationstest-Befund

Nicht in Anführungszeichen gesetzte Dienstpfade gehören konstant zu den häufigsten Privilegieneskalationsvektoren, die in Windows-Unternehmensumgebungen gefunden werden.

Drittanbieter-Software-Schwachstellen

Viele kommerzielle Anwendungen installieren Dienste mit Pfaden ohne Anführungszeichen, einschließlich Sicherheitssoftware, Backup-Lösungen und Enterprise-Management-Tools.

Malware-Persistenz

Malware-Familien haben die Ausnutzung von Pfaden ohne Anführungszeichen für Persistenz und Privilegieneskalation verwendet.


Tools zum Testen/Ausnutzen

  • PowerUp — PowerShell-Privilegieneskalationstool.

  • WinPEAS — Windows-Privilegieneskalationsscanner.

  • Metasploit — exploit/windows/local/unquoted_service_path.

  • BeRoot — Privilegieneskalationstool.


CVE-Beispiele


Referenzen

  1. MITRE. "CWE-428: Unquoted Search Path or Element." https://cwe.mitre.org/data/definitions/428.html

  2. Microsoft. "CreateProcess function." https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa