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
| Auswirkung | Details |
|---|---|
| Zugriffskontrolle | Umfang: Privilegieneskalation Angreifer können Code mit erhöhten Privilegien (oft SYSTEM) ausführen. |
| Integrität | Umfang: Systemkompromittierung Bösartiger Code läuft anstelle legitimer Dienst-Executables. |
| Verfügbarkeit | Umfang: 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
-
CVE-2019-6453 — Mattermost Pfad ohne Anführungszeichen.
-
CVE-2018-16157 — Ivanti Pfad ohne Anführungszeichen.
-
CVE-2020-5316 — Dell Pfad ohne Anführungszeichen.
Referenzen
-
MITRE. "CWE-428: Unquoted Search Path or Element." https://cwe.mitre.org/data/definitions/428.html
-
Microsoft. "CreateProcess function." https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa