
Reproductor contenerizado para la escalada de privilegios en Linux CVE-2021-22555, con perfiles de mitigación seccomp y guía de despliegue para clústeres Kubernetes y OpenShift.
Primero, esto incluye el código del exploit desde aquí como un contenedor preconstruido práctico: https://github.com/google/security-research/tree/master/pocs/linux/cve-2021-22555
Contenedor preconstruido: quay.io/cgwalters/cve-2021-22555
Una mitigación sólida es habilitar seccomp que deniegue clone(CLONE_NEWUSER). La documentación oficial de Kubernetes
tiene algo de información sobre esto, pero deja la implementación de la política en el nodo al usuario. En OpenShift 4, tenemos el machine-config-operator
que puede manejar esto.
Seccomp no se discute realmente en la documentación oficial. Sin embargo, la guía de seguridad al menos menciona algo de esto, al igual que este blog.
cri-o en 4.7 incluye una política seccomp predeterminada, pero no está habilitada por defecto.
podman y docker también incluyen una política, y sí está habilitada por defecto (pero difieren, ver más abajo).
La política de cri-o no deniega clone(CLONE_NEWUSER) por defecto - y esto también es cierto para la política de podman. Sin embargo, la política predeterminada de docker sí deniega clone(CLONE_NEWUSER):
[root@cosa-devsh ~]# rpm -q podman moby-engine
podman-3.1.2-1.fc33.x86_64
moby-engine-19.03.13-1.ce.git4484c46.fc33.x86_64
[root@cosa-devsh ~]# podman run --rm -ti registry.fedoraproject.org/fedora:34 /bin/sh -c 'unshare -U --keep-caps true'
[root@cosa-devsh ~]# echo $?
0
[root@cosa-devsh ~]# docker run --rm -ti registry.fedoraproject.org/fedora:34 /bin/sh -c 'unshare -U --keep-caps true'
unshare: unshare failed: Operation not permitted
errchan: json: cannot unmarshal array into Go struct field systemdEventMessage.MESSAGE of type string
[root@cosa-devsh ~]# echo $?
1
[root@cosa-devsh ~]#
O en otras palabras: docker no es vulnerable a esto por defecto, pero podman y cri-o sí lo son. (TODO: verificar containerd)
La entrada de blog openshift/seccomp-for-fun-and-profit discute algo de esto, y enlaza a un perfil que el autor generó. Esta política sí deniega clone(CLONE_NEWUSER).
Por conveniencia, este repositorio contiene una copia de ese perfil en more-restricted.json, y un archivo Butane que genera un objeto MachineConfig que implementará ese perfil en los workers.
Use el archivo de pod de ejemplo que tiene:
securityContext:
seccompProfile:
type: Localhost
localhostProfile: more-restricted.json
Obtenemos:
$ oc logs pod/cve-2021-22555
[+] Linux Privilege Escalation by theflow@ - 2021
[+] STAGE 0: Initialization
[*] Setting up namespace sandbox...
[-] unshare(CLONE_NEWUSER): Operation not permitted
Lo cual debería hacer que el exploit sea inalcanzable.
Sin embargo, esto requiere que los pods opten por participar. Aún TODO: Explorar si una política seccomp puede hacerse obligatoria mediante un SecurityContextConstraint, o si necesitamos un webhook de admisión mutante.