flawopen.com/Teardowns/cve-2024-5321-kubernetes-windows-container-log-permissions

● CVE-2024-5321 · CVSS 6.1 · Mittel
Sicherheitsforschung · FlawOpen

CVE-2024-5321: Berechtigungen der Container-Logs auf Windows-Knoten in Kubernetes

CVE-2024-5321 (CVSS 6.1, mittel): Auf Windows-Knoten legte das Kubelet die Pod-Log-Verzeichnisse mit os.MkdirAll an, das unter Windows den Berechtigungsmodus ignoriert; die Logs erbten eine ACL, die BUILTIN\Users Lesen und Authenticated Users Ändern erlaubte.

💡 Einfache Erklärung (ELI5)

Ein Krankenhaus bewahrt jede Patientenakte in einem Aktenschrank auf. Wer einen neuen Schrank bestellt, schreibt „nur Ärzte“ aufs Bestellformular – doch in diesem Gebäude wird das Schloss-Feld stillschweigend ignoriert, und der Schrank übernimmt die Standardregel des Raums: Jeder Angestellte darf lesen, jeder mit Ausweis darf hineinschreiben. Die Lösung ist ein Mitarbeiter, der jedem neuen Schrank ein eigenes Schloss einbaut und für diesen Schrank die Raumregel außer Kraft setzt.

Kernkonzepte & Begriffe

DACL / ACE
Die Discretionary Access Control List von Windows: die Einträge, die festlegen, welche Konten eine Datei oder ein Verzeichnis lesen, schreiben oder ausführen dürfen.
ACL-Vererbung
Standardmäßig übernimmt eine neue Windows-Datei bzw. ein neues Verzeichnis die vererbbaren Einträge der DACL des übergeordneten Verzeichnisses. Eine geschützte DACL verhindert das.
BUILTIN\Users / Authenticated Users
Breite Windows-Gruppen: alle lokalen Konten bzw. alle Konten, die sich überhaupt angemeldet haben. Kubernetes ordnet Container, die als ContainerUser laufen, beim Zugriff auf Host-Dateien BUILTIN\Users zu.
os.MkdirAll unter Windows
Gos os.MkdirAll(path, perm) wertet perm nur unter Unix aus. Unter Windows wird der Modus ignoriert und das Verzeichnis erhält die geerbte ACL.

Ursachenanalyse

setupDataDirs() in pkg/kubelet/kubelet.go legte das Pod-Log-Stammverzeichnis (C:\var\log\pods) mit os.MkdirAll(dir, 0750) an. Go ignoriert den Modus unter Windows, daher erbten das Verzeichnis und die darin geschriebenen Logdateien die ACL des Elternverzeichnisses, die BUILTIN\Users Lese- und NT AUTHORITY\Authenticated Users Änderungsrechte gab. PR #126104 ergänzte in pkg/util/filesystem die Funktionen MkdirAll() und Chmod(), die den Unix-Modus in eine explizite DACL übersetzen und mit PROTECTED_DACL_SECURITY_INFORMATION setzen, und stellte die Log-, Plugin- und Checkpoint-Verzeichnisse des Kubelets darauf um.

Schritt-für-Schritt Angriffsablauf

Schritt 1

Das Kubelet legt das Log-Verzeichnis an

Auf einem Windows-Knoten ruft setupDataDirs() os.MkdirAll(kl.getPodLogsDir(), 0750) auf. Die 0750 wird ignoriert, das Verzeichnis erbt die ACL des Elternverzeichnisses.

Schritt 2

Breite Gruppen erben Zugriff

Die geerbten Einträge geben BUILTIN\Users Lesezugriff und NT AUTHORITY\Authenticated Users Änderungszugriff auf die Pod-Log-Verzeichnisse und die Dateien, die die Runtime dort schreibt.

Schritt 3

Fremde Workload-Logs lesen

Jedes niedrig privilegierte lokale Konto auf dem Knoten oder ein Workload, der den Log-Pfad per hostPath einbindet, liest stdout und stderr anderer Pods – oft mit Tokens, Verbindungszeichenfolgen oder Kundendaten.

Schritt 4

Beweise manipulieren

Dieselben Konten können Logdateien bearbeiten oder kürzen, bevor ein Log-Shipper sie einsammelt, und so Aktivitäten vor dem zentralen Logging verbergen.

Quellcode: Verwundbar vs. Sicher

VERWUNDBARE IMPLEMENTIERUNG
// pkg/kubelet/kubelet.go (kubelet v1.30.2)
func (kl *Kubelet) setupDataDirs() error {
	if err := os.MkdirAll(kl.getRootDir(), 0750); err != nil {
		return fmt.Errorf("error creating root directory: %v", err)
	}
	// BUG on Windows: os.MkdirAll ignores the 0750 mode. The directory inherits
	// its parent's ACL, which lets BUILTIN\Users read and
	// NT AUTHORITY\Authenticated Users modify every pod's log files.
	if err := os.MkdirAll(kl.getPodLogsDir(), 0750); err != nil {
		return fmt.Errorf("error creating pod logs root directory %q: %w", kl.getPodLogsDir(), err)
	}
	if err := os.MkdirAll(kl.getPodsDir(), 0750); err != nil {
		return fmt.Errorf("error creating pods directory: %v", err)
	}
	return nil
}
GEHÄRTETER SICHERHEITS-PATCH
// pkg/kubelet/kubelet.go (fixed in v1.30.3, PR #126104)
func (kl *Kubelet) setupDataDirs() error {
	if err := os.MkdirAll(kl.getRootDir(), 0750); err != nil {
		return fmt.Errorf("error creating root directory: %v", err)
	}
	// FIX: utilfs.MkdirAll is plain os.MkdirAll on Linux. On Windows it also
	// calls utilfs.Chmod, which replaces the inherited ACL with an explicit one.
	if err := utilfs.MkdirAll(kl.getPodLogsDir(), 0750); err != nil {
		return fmt.Errorf("error creating pod logs root directory %q: %w", kl.getPodLogsDir(), err)
	}
	if err := os.MkdirAll(kl.getPodsDir(), 0750); err != nil {
		return fmt.Errorf("error creating pods directory: %v", err)
	}
	return nil
}

// pkg/util/filesystem/util_windows.go
func MkdirAll(path string, perm os.FileMode) error {
	if err := os.MkdirAll(path, perm); err != nil {
		return fmt.Errorf("Error creating directory %s: %v", path, err)
	}
	return Chmod(path, perm)
}

func Chmod(path string, filemode os.FileMode) error {
	// Maps owner, group and other mode bits to ACEs for the file's owner SID,
	// its group SID and BUILTIN\Users (BU). For 0750 the result is
	// "D:(A;OICI;FA;;;<owner>)(A;OICI;FRFX;;;<group>)(A;OICI;;;;BU)".
	// (Abridged: the real function builds this string inline.)
	dacl, err := daclForMode(path, filemode)
	if err != nil {
		return err
	}
	newSD, err := windows.SecurityDescriptorFromString(dacl)
	if err != nil {
		return fmt.Errorf("Error creating new security descriptor from DACL string: %v", err)
	}
	newDACL, _, err := newSD.DACL()
	if err != nil {
		return fmt.Errorf("Error getting DACL from new security descriptor: %v", err)
	}
	// PROTECTED_DACL_SECURITY_INFORMATION blocks inheritance from the parent,
	// so the BUILTIN\Users and Authenticated Users entries no longer apply.
	return windows.SetNamedSecurityInfo(path, windows.SE_FILE_OBJECT,
		windows.DACL_SECURITY_INFORMATION|windows.PROTECTED_DACL_SECURITY_INFORMATION,
		nil, nil, newDACL, nil)
}

Checkliste für Engineering & Systemsicherheit

Quellen