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

● CVE-2024-5321 · CVSS 6.1 · Media
Investigación · FlawOpen

CVE-2024-5321: permisos de los registros de contenedores en nodos Windows de Kubernetes

CVE-2024-5321 (CVSS 6.1, media): en nodos Windows, el kubelet creaba los directorios de registros de los pods con os.MkdirAll, que ignora el modo de permisos en Windows; los registros heredaban una ACL que permitía a BUILTIN\Users leerlos y a Authenticated Users modificarlos.

💡 Explicación en Lenguaje Sencillo (ELI5)

Un hospital guarda la historia clínica de cada paciente en un archivador. Al pedir un archivador nuevo, el personal escribe "solo médicos" en el formulario, pero en este edificio el campo de la cerradura se ignora sin avisar y el archivador se queda con la regla por defecto de la sala: cualquier empleado puede leerlo y cualquiera con tarjeta puede escribir en él. La solución es un administrativo que, cada vez que llega un archivador, le pone su propia cerradura y anula para ese mueble la regla por defecto de la sala.

Conceptos Clave y Términos

DACL / ACE
Lista de control de acceso discrecional de Windows: las entradas que indican qué cuentas pueden leer, escribir o ejecutar un archivo o directorio.
Herencia de ACL
Por defecto, un archivo o directorio nuevo en Windows copia las entradas heredables de la DACL de su directorio padre. Una DACL protegida lo impide.
BUILTIN\Users / Authenticated Users
Grupos amplios de Windows: todas las cuentas locales y todas las cuentas que han iniciado sesión alguna vez. Kubernetes asocia los contenedores que se ejecutan como ContainerUser a BUILTIN\Users cuando acceden a archivos del host.
os.MkdirAll en Windows
os.MkdirAll(path, perm) de Go solo usa perm en Unix. En Windows el modo se ignora y el directorio recibe la ACL heredada.

Análisis de Causa Raíz

setupDataDirs() en pkg/kubelet/kubelet.go creaba la raíz de registros de los pods (C:\var\log\pods) con os.MkdirAll(dir, 0750). Go ignora el modo en Windows, así que el directorio y los archivos de registro escritos en él heredaban la ACL del padre, que daba lectura a BUILTIN\Users y modificación a NT AUTHORITY\Authenticated Users. El PR #126104 añadió MkdirAll() y Chmod() en pkg/util/filesystem, que traducen el modo Unix a una DACL explícita aplicada con PROTECTED_DACL_SECURITY_INFORMATION, y cambió a ellas los directorios de registros, plugins y checkpoints del kubelet.

Flujo de Ataque Paso a Paso

Paso 1

El kubelet crea la raíz de registros

En un nodo Windows, setupDataDirs() llama a os.MkdirAll(kl.getPodLogsDir(), 0750). El 0750 se ignora y el directorio hereda la ACL de su padre.

Paso 2

Grupos amplios heredan acceso

Las entradas heredadas dan lectura a BUILTIN\Users y modificación a NT AUTHORITY\Authenticated Users sobre los directorios de registros de los pods y los archivos que el runtime escribe en ellos.

Paso 3

Lectura de registros ajenos

Cualquier cuenta local con pocos privilegios en el nodo, o una carga con la ruta de registros montada por hostPath, lee el stdout y el stderr de otros pods, que a menudo contienen tokens, cadenas de conexión o datos de clientes.

Paso 4

Manipulación de las pruebas

Las mismas cuentas pueden editar o truncar archivos de registro antes de que el agente de envío los recoja, ocultando actividad al registro centralizado.

Código Fuente: Vulnerable vs. Seguro

IMPLEMENTACIÓN VULNERABLE
// 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
}
PARCHE SEGURO Y ROBUSTO
// 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)
}

Lista de Verificación de Seguridad para Ingeniería

Fuentes