Vulnerabilidad «Dirty Pipe» de Linux y tus aplicaciones en contenedores (CVE-2022-0847)
9 de marzo de 2022
0 minutos de lectura¿Qué es la vulnerabilidad «Dirty Pipe»? (CVE-2022-0847)
Recientemente, CVE-2022-0847 describió una falla en el kernel de Linux que puede explotarse para permitir que cualquier proceso modifique archivos, independientemente de sus permisos o propietario. La comunidad de seguridad la bautizó «Dirty Pipe» por su similitud con «Dirty COW», una vulnerabilidad de escalación de privilegios reportada en CVE-2016-5195, y porque la falla se encuentra en la implementación de tuberías del kernel. Si quieres profundizar, en la base de datos de vulnerabilidades Snyk Intel hay varias referencias a esta vulnerabilidad.
En este artículo, hablaremos de los riesgos que enfrentan tus cargas de trabajo en contenedores y veremos cómo un actor malicioso puede modificar el contenido de las imágenes de contenedor y otros archivos que normalmente son de solo lectura, independientemente de su UID y de los permisos del sistema de archivos.
Primero, veamos qué puedes hacer ahora mismo para proteger tus sistemas de Dirty Pipe.
En resumen: actualiza tus hosts Linux
La única solución conocida para esta vulnerabilidad es actualizar tus hosts Linux a una de estas versiones del kernel:
5.16.11
5.15.25
5.10.102
No hay otras opciones de mitigación que puedan proteger tus sistemas si un actor malicioso obtiene acceso a tu entorno.
Cómo afecta Dirty Pipe a tus imágenes de contenedor
Conceptos básicos de las imágenes de contenedor

Una imagen de contenedor está formada, básicamente, por un conjunto de capas superpuestas. Cuando se inicia un contenedor, el motor de ejecución (Docker, containerD, cri-O, etc.) combina estas capas y presenta el conjunto resultante como el sistema de archivos del proceso. Estas capas siempre son de solo lectura; cualquier modificación se realiza en una capa de lectura y escritura que se crea específicamente para cada instancia del contenedor mediante un patrón de copia en escritura (COW). Esta capa de lectura y escritura es temporal, ya que se destruye cuando se elimina el contenedor del sistema. También se puede omitir si el contenedor se inicia en modo de solo lectura, lo que hace que sea inmutable.
Es habitual recomendar que los procesos de los contenedores se ejecuten como usuarios sin privilegios y que sus sistemas de archivos raíz sean de solo lectura. Estas medidas dificultan mucho que un actor malicioso aproveche las vulnerabilidades de una aplicación para ampliar su ataque, ya que le complican introducir código o scripts propios en el sistema de archivos del contenedor. Consulta nuestra guía de seguridad de contenedores para conocer otras prácticas recomendadas.
Explotación de Dirty Pipe en un contenedor
Los detalles del funcionamiento de la vulnerabilidad Dirty Pipe quedan fuera del alcance de este artículo —consulta el blog original sobre su descubrimiento para conocer todos los detalles—, pero, a grandes rasgos, se pueden seguir unos pasos relativamente sencillos para cambiar el contenido de casi cualquier archivo, incluso si sus permisos o propietario impiden hacerlo. Por ejemplo, con el código de prueba de concepto write_anything del artículo enlazado arriba, crearemos una imagen con este Dockerfile:

Luego, lo ejecutamos en modo de solo lectura y usamos el ejecutable write_anything para cambiar /etc/passwd.

No debería haber podido hacerlo porque el archivo es de solo lectura, pertenece al usuario root y está en un sistema de archivos raíz de solo lectura.
Luego, detengamos y eliminemos este contenedor, iniciemos uno nuevo y revisemos /etc/passwd en el nuevo contenedor.

El cambio en el archivo persistió porque el proceso del contenedor anterior modificó el contenido real de la capa de la imagen, que es de solo lectura en el sistema host. El cambio permanecerá en este host hasta que se elimine o reemplace la imagen.
Capa de imagen de bajo nivel antes de ejecutar el ataque

Capa de imagen de bajo nivel después de ejecutar el ataque

De hecho, si tienes varios contenedores en el mismo host, cualquier contenedor que comparta esta capa base de la imagen podría ver el cambio de inmediato (excepto los que ya hayan modificado el mismo archivo en su propia capa de lectura y escritura).
Tres contenedores supervisan sus archivos /etc/passwd con watch mientras un cuarto ejecuta el ataque write_anywhere.

Dirty Pipe pone en riesgo todos los volúmenes montados desde el host

Quizás hayas oído que montar volúmenes del host (también llamados montajes bind) en tus contenedores nunca es una buena idea. En condiciones normales, se recomienda evitarlo porque una configuración incorrecta sencilla podría otorgarle al contenedor acceso no previsto para modificar archivos del host. Dirty Pipe agrava el problema, porque este exploit pone en riesgo los volúmenes montados desde el host, incluso si se montaron con la marca :ro.

Escalación de privilegios mediante Dirty Pipe
Uno de los ejemplos de prueba de concepto del exploit que circulan aprovecha esta falla para obtener privilegios elevados: modifica un binario existente con habilitación suid para eludir las protecciones habituales. No es un problema exclusivo de los contenedores, pero puede explotarse dentro de ellos. Por ejemplo, un atacante podría aprovechar una vulnerabilidad de ejecución remota de código (RCE) en una aplicación e inyectar este código de prueba de concepto para convertirse en root dentro del contenedor. Esto permite eludir las configuraciones del contenedor o de Kubernetes que limitan este tipo de comportamiento.
¿Hay alguna forma de mitigarla?
Como mencionamos arriba, actualizar los sistemas host es la única forma conocida de protegerlos de esta vulnerabilidad. Los motores de contenedores y las medidas de mitigación de Kubernetes operan en un nivel demasiado alto como para ofrecer mucha protección contra un exploit de nivel de kernel como este.
¿No basta con actualizar las imágenes base?
Lamentablemente, no. La falla no está en el sistema de archivos de ninguna imagen base, sino en el kernel de los servidores host, que comparten todos los contenedores en ejecución. Puedes comprobarlo ejecutando uname -a en varios contenedores basados en distintas imágenes: todos mostrarán la versión del kernel del host.

¿Qué pasa con SecurityContext de Kubernetes?
Las configuraciones de SecurityContext de Kubernetes, como readonlyRootFilesystem:true, runAsNonRoot:true, runAsUser: y AllowPrivilegeEscalation:false, son ineficaces porque cualquier usuario puede aprovechar esta vulnerabilidad y eludirlas.
Esto no significa que debas dejar de usar estas configuraciones. Al contrario, son excelentes ejemplos de defensa en profundidad y protegerán tus clústeres de muchos otros tipos de ataque.
De hecho, tenemos una guía rápida de seguridad de Kubernetes que explica las configuraciones de SecurityContext y por qué deberías usarlas para reforzar las implementaciones de tus aplicaciones en Kubernetes. También puedes analizar tus manifiestos de Kubernetes con las herramientas gratuitas de análisis de IaC de Snyk para encontrar y corregir errores de configuración como estos. Haz clic en el enlace de abajo para empezar a usarlas hoy.
Conclusión
Si aún no lo hiciste, actualiza tus hosts de inmediato. Si alguno de los temas anteriores despertó tu interés, consulta estos enlaces para profundizar.
Blog de CM4All: Artículo sobre el descubrimiento de la vulnerabilidad Dirty Pipe
Blog de Snyk: Descubre los detalles sobre la creación de imágenes, las capas y el análisis de vulnerabilidades en contenedores
Guía rápida de Snyk: 10 configuraciones de contexto de seguridad de Kubernetes que debes conocer
ArsTechnica: Linux ha sufrido la vulnerabilidad de mayor gravedad en años
Protege la infraestructura desde el origen
Snyk automatiza la seguridad y el cumplimiento de IaC en los flujos de trabajo, y detecta recursos con desviaciones de configuración y recursos faltantes.
