
Caso de estudio educativo y guía de desarrollo de exploits para CVE-2022-0185, un desbordamiento de búfer en el heap del kernel de Linux que permite escalada local de privilegios. Incluye POC, depuración con QEMU y exploit para Ubuntu con análisis técnico detallado.
Este estudio de caso es el resultado de una tarea de ECE 9069: Introducción al Hacking: https://whisperlab.org/introduction-to-hacking/
CVE-2022-0185 es una vulnerabilidad de desbordamiento de búfer basado en montón que se encontró en la forma en que la función legacy_parse_param en la funcionalidad de Contexto de Sistema de Archivos (Filesystem Context) del kernel de Linux verificaba la longitud de los parámetros suministrados. Un usuario local sin privilegios (en caso de que los espacios de nombres de usuario sin privilegios estén habilitados; de lo contrario, necesita el privilegio CAP_SYS_ADMIN dentro de un espacio de nombres) capaz de abrir un sistema de archivos que no admita la API de Contexto de Sistema de Archivos (y por lo tanto recurre al manejo heredado) podría usar esta falla para escalar sus privilegios en el sistema. [1]
Después de que se reportó esta vulnerabilidad, se lanzó un parche para corregir este error:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=722d94847de2
https://ubuntu.com/security/CVE-2022-0185#impact-score
Hay un artículo detallado del explorador: https://www.hackthebox.com/blog/CVE-2022-0185:_A_case_study
En este repositorio explicaré los pasos básicos y la información de antecedentes relacionada para reproducir esta vulnerabilidad. Además, si hay algo que no te quede claro, puedes enviarme un correo electrónico a [email protected]. Estaré encantado de responder tus preguntas.
La vulnerabilidad CVE-2022-0185 se publicó el 02/11/2022, con una puntuación base CVSS 3.x de 8.4 (Alta).[1] Esta vulnerabilidad es un desbordamiento de búfer basado en montón, causado por un desbordamiento por debajo de entero sin signo (unsigned integer underflow).
La vulnerabilidad se introdujo en el kernel de Linux v5.1, afectando a todas las distribuciones de Linux con versiones de kernel superiores a 5.1. Por ejemplo, Ubuntu 20.04 LTS (focal) era vulnerable a este error. Sin embargo, se lanzó un parche y está disponible desde la versión 5.4.0-96.109.[3]
Explotar esta vulnerabilidad permite que un usuario local sin privilegios escale sus privilegios en el sistema, comprometiendo potencialmente todo el sistema.[1][2] Aquí hay un análisis detallado de la puntuación CVSS: Puntuación Base: 8.4, lo que indica un riesgo de seguridad significativo que requiere atención inmediata. Puntuación de Impacto: 5.9, sugiriendo un daño potencial sustancial si se explota. Los valores altos de confidencialidad, integridad y disponibilidad contribuyen a esta puntuación. Puntuación de Explotabilidad: 2.5, sugiriendo una explotabilidad relativamente alta. El vector de ataque local, la alta integridad y los altos valores de disponibilidad contribuyen a esta puntuación.
La Tabla 1.1 y la Tabla 1.2 proporcionan más información sobre estas puntuaciones y sus componentes.
| Severidad CVSS v3.1 | Valor |
|---|---|
| Puntuación Base | 8.4 ALTA |
| Puntuación de Impacto | 5.9 |
| Puntuación de Explotabilidad | 2.5 |
Tabla 1.1 Puntuaciones de Severidad CVSS[1]
| Métricas CVSS v3.1 | Valor |
|---|---|
| Vector de Ataque (AV) | Local |
| Privilegios Requeridos (PR) | Ninguno |
| Interacción del Usuario (UI) | Ninguno |
| Confidencialidad (C) | Alta |
| Integridad (I) | Alta |
| Disponibilidad (A) | Alta |
Tabla 1.2 Vector CVSS[1]
En las computadoras modernas existen dos tipos de enteros: con signo y sin signo. La representación de números con signo generalmente implica una operación llamada complemento a dos.[4] "El complemento a dos utiliza el dígito binario con el mayor valor posicional como signo para indicar si el número binario es positivo o negativo".[4]
La introducción del complemento a dos convierte el cálculo de la resta en una suma, simplificando así el diseño y la implementación de la CPU. La generación del complemento a dos de un entero involucra tres pasos:[4]
La Fig 2.1.1.1 muestra el proceso de conversión en un diagrama con un ejemplo real de conversión de "-6" a su formato de complemento a dos.

Fig 2.1.1.2 Suma Usando Complemento a Dos
La Figura 2.1.1.2 muestra el proceso de sumar el complemento a dos de '-6' a '+6'. Esto demuestra cómo el uso del complemento a dos permite que la suma se utilice como sustituto de la resta.

Fig 2.1.1.2 Suma Usando Complemento a Dos
En la Sección 2.1.1, ya entendemos qué es el complemento a dos. Ahora, veamos el escenario del desbordamiento por debajo de números sin signo en las computadoras. En las computadoras modernas, al usar números sin signo, el bit más significativo no se trata como un bit de signo; en cambio, es parte del número sin signo en sí. Esta situación significa que al realizar una resta con un número sin signo, debemos tener cuidado, ya que puede llevar a una condición conocida como desbordamiento por debajo de número sin signo.[5]
La Fig 2.1.2.1 ilustra la situación de restar 6 de 5 para un número sin signo de 8 bits. El resultado final es 255 debido al envolvimiento del número sin signo. Cuando este desbordamiento por debajo ocurre en una declaración condicional, tiene el potencial de interrumpir la funcionalidad de la declaración.

Fig 2.1.2.1 Desbordamiento por Debajo de Número Sin Signo
En el kernel de Linux, el Asignador de Slabs (Slab Allocator) es un mecanismo de gestión de memoria utilizado para la asignación y liberación eficiente de pequeños fragmentos de memoria. Ofrece rendimiento al mantener varios cachés de Slabs, cada uno conteniendo bloques de memoria de tamaño fijo. Típicamente, kmalloc-32 asigna 32 bytes de memoria, es un slab kmalloc-32, mientras que kmalloc-4k asigna 4096 bytes de memoria, es un slab kmalloc-4k.[6]
Además, la asignación de slabs en el kernel de Linux típicamente implica asignar memoria desde un espacio de direcciones contiguo dentro de la región de memoria heap del kernel. Esta dirección contigua es gestionada por el kernel y se utiliza para asignar memoria para varios objetos y estructuras de datos del kernel. La Fig 2.2.1.1 muestra la disposición de los slabs en la memoria del kernel de Linux.

Fig 2.2.1.1 Asignador de Slabs en Linux [7] (El autor de esta figura es https://leviathan.vip/)
Si deseas reproducir el proceso con un kernel de Linux compilado por ti mismo, lee los siguientes archivos markdown para obtener la información de antecedentes: