
Prueba de concepto de dos etapas para CVE-2021-3493, explotando Ubuntu OverlayFS para escalar de usuario no privilegiado a root mediante manipulación de capacidades de archivos en espacios de nombres de usuario.
Una prueba de concepto funcional para CVE-2021-3493, una vulnerabilidad de escalada de privilegios local en la implementación de OverlayFS del kernel de Ubuntu.
Un usuario sin privilegios puede montar un sistema de archivos overlay dentro de un namespace de usuario y establecer capacidades de archivo arbitrarias mediante setxattr. El kernel no valida el origen de estas capacidades en los namespaces, por lo que surten efecto en el namespace de usuario init — lo que permite a cualquier usuario local escalar a root.
Esta vulnerabilidad es específica de Ubuntu. Ubuntu incluye un parche (FS_USERNS_MOUNT) que permite montajes overlay sin privilegios — los kernels oficiales no lo incluyen, por lo que Linux mainline y otras distribuciones generalmente no están afectados.
| Distribución | Kernel | Vulnerable (corregido en) |
|---|---|---|
| Ubuntu 20.10 | 5.8 | < 5.8.0-50 |
| Ubuntu 20.04 LTS | 5.4 | < 5.4.0-72 |
| Ubuntu 18.04 LTS | 4.15 | < 4.15.0-142 |
| Ubuntu 18.04 LTS (HWE) | 5.3 | < 5.3.0-73 |
| Ubuntu 16.04 LTS | 4.4 | < 4.4.0-209 |
| Ubuntu 14.04 ESM (HWE) | 4.4 | < 4.4.0-209 |
Fuente: USN-4916-1
Este PoC utiliza un diseño de dos etapas:
| Archivo | Función |
|---|---|
exploit.c | Etapa 1 — Crea un sistema de archivos overlay dentro de un namespace de usuario, copia el payload rootshell en él y establece el xattr security.capability con todas las capacidades (all+ep) |
¿Por qué dos etapas? El PoC original inspiringz/CVE-2021-3493 hace que el exploit ejecute (exec) un shell desde dentro del namespace de usuario, por lo que uid=0 es solo una asignación del namespace, no root real. Este PoC separa la configuración del overlay (proceso hijo en el namespace de usuario) de la ejecución del payload (proceso padre en el namespace init), lo que garantiza una escalada de privilegios genuina.
exploit (init ns, uid=1000)
│
├─ fork → child (user ns)
│ ├─ unshare(CLONE_NEWUSER | CLONE_NEWNS)
│ ├─ mount overlayfs
│ ├─ copy rootshell → overlay merge dir
│ ├─ setxattr("security.capability", all+ep) ← vulnerability trigger
│ └─ exit
│
└─ parent (init ns, uid=1000)
└─ execl("upper/rootshell")
├─ kernel loads file capabilities in init ns
│ CapPrm: 0000003fffffffff
│ CapEff: 0000003fffffffff
├─ setuid(0) → success
├─ setgid(0) → success
└─ exec /bin/bash → real root shell
/dev/shm → /tmp: El original utiliza /dev/shm, que está montado con nosuid, lo que hace que el kernel ignore silenciosamente las capacidades de archivo al ejecutar. Este PoC utiliza /tmp (normalmente en ext4 sin nosuid).
Payload de dos etapas: El original se copia a sí mismo (/proc/self/exe) como el binario que porta las capacidades, pero como el exploit llama a unshare, re-ejecutarlo simplemente vuelve a entrar en un namespace de usuario. Este PoC utiliza un binario separado rootshell que consume directamente las capacidades.
| SO | Ubuntu 20.04.1 LTS (Focal Fossa) |
| Kernel | 5.4.0-65-generic (vulnerable) / 5.4.0-216-generic (parcheado) |
| Configuración | Instalación por defecto de Ubuntu Server — sin mitigaciones deshabilitadas |
El host de prueba utiliza un kernel estándar de Ubuntu 20.04 con todas las características de seguridad predeterminadas intactas:
CONFIG_USER_NS=y + kernel.unprivileged_userns_clone=1 (predeterminado — permite namespaces de usuario sin privilegios)CONFIG_OVERLAY_FS=m (predeterminado — OverlayFS disponible como módulo)BOOT_IMAGE=... root=... ro)No es necesario deshabilitar ninguna característica de seguridad — el exploit funciona directamente en Ubuntu 20.04 por defecto con un kernel vulnerable.
⚠️ ADVERTENCIA: Ejecute esto solo en sistemas que le pertenezcan o para los que tenga autorización explícita de pruebas. Este exploit otorga acceso root real.
make
./exploit
El comportamiento predeterminado lanza un shell root interactivo. También puede ejecutar un solo comando:
./exploit "id && cat /etc/shadow"
============================================
CVE-2021-3493 OverlayFS Privilege Escalation
Kernel: 5.4.0-65-generic
User: uid=1000(user) gid=1000(user)
============================================
[1] Setting up overlay filesystem in user namespace...
[2] File capabilities set on /tmp/.ovlcap/upper/rootshell
[3] Executing rootshell from init namespace...
[*] Before privilege escalation:
uid=1000(user) gid=1000(user)
[*] Process capabilities:
CapInh: 0000000000000000
CapPrm: 0000003fffffffff
CapEff: 0000003fffffffff
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
[+] After setuid(0) + setgid(0):
uid=0(root) gid=0(root)
root@host:~#
make clean
Los kernels parcheados (p. ej. >= 5.4.0-70 en Ubuntu 20.04) actualizan el xattr de capacidades del formato v2 a v3 cuando se establece a través de un overlay en un namespace de usuario. El formato v3 incluye un campo rootid que registra el UID real de quien lo establece en el namespace init. Al ejecutar, el kernel comprueba rootid — si no es 0, las capacidades se rechazan:
# Vulnerable kernel (5.4.0-65) — v2 format, no rootid
security.capability = 0x01000002 ffffffff00000000 ffffffff00000000
# Patched kernel (5.4.0-70+) — v3 format, rootid=1000
security.capability = 0x01000003 ffffffff00000000 ffffffff00000000 e8030000
^^ ^^^^^^^^
v3 rootid=1000
Este código se proporciona solo para investigación de seguridad y pruebas autorizadas. Úselo únicamente en sistemas que le pertenezcan o para los que tenga permiso escrito explícito de pruebas. Los autores no asumen ninguna responsabilidad por el mal uso.
rootshell.c | Etapa 2 — Un payload limpio que aprovecha las capacidades de archivo para llamar a setuid(0) y lanzar un shell root real |