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
harden-docker-seccomp — Mitigación de Docker para CVE-2026-31431 ('Copy Fail'). Incluye también plantillas de Kubernetes. | Kitploit
Herramientas/GitHubGitHub/devstuff/harden-docker-seccomp
Seguridad de Infraestructura en la NubeHerramientas DefensivasSeguridad de ContenedoresAnálisis de VulnerabilidadesAuditoría de ConfiguraciónDevSecOps
GitHubdevstuff/harden-docker-seccomp

harden-docker-seccomp

Mitigación de Docker para CVE-2026-31431 ('Copy Fail'). Incluye también plantillas de Kubernetes.

Ver Repositorio
21hace 3 mesesAún no revisado

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

harden-docker-seccomp

Script idempotente para bloquear la creación de sockets AF_ALG para todos los contenedores Docker en un host como mitigación para CVE-2026-31431 ("Copy Fail").

Antecedentes

CVE-2026-31431 es una escalada de privilegios local en la plantilla criptográfica authencesn del kernel de Linux, presente en kernels compilados entre 2017 y la disponibilidad del parche oficial (commit de mainline a664bf3d603d). Un usuario sin privilegios puede encadenar una operación de socket AF_ALG con splice() para realizar una escritura controlada de 4 bytes en la caché de páginas de cualquier archivo legible, apuntando a un binario setuid para obtener una shell root. Una prueba de concepto en Python de 732 bytes explota esto de forma fiable, sin condiciones de carrera ni offsets por distribución, en todas las principales distribuciones de Linux que incluyen un kernel afectado.

El primer paso obligatorio del exploit es abrir un socket AF_ALG (socket(AF_ALG, SOCK_SEQPACKET, 0)). Bloquear esa syscall mediante seccomp previene la explotación incluso en kernels sin parche. El perfil seccomp predeterminado integrado de Docker no bloquea , y no es suficiente: los clústeres probados mostraron que los pods admitidos bajo PSS Restricted aún podían abrir sockets .

AF_ALG
RuntimeDefault
AF_ALG

Consulte el aviso del investigador original en https://copy.fail y el aviso de CERT-EU en https://cert.europa.eu/publications/security-advisories/2026-005/ para obtener detalles técnicos completos y disponibilidad de parches por distribución.

Alcance de esta herramienta

Este script cubre la configuración global del daemon de Docker Engine. Para Kubernetes, consulte la sección de Kubernetes a continuación. Para cargas de trabajo en bare-metal o VM (no contenedorizadas), deshabilite el módulo del kernel algif_aead en su lugar:

root@kitploit:~
echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif.conf
rmmod algif_aead 2>/dev/null || true

Ese enfoque no tiene impacto en dm-crypt/LUKS, kTLS, IPsec/XFRM, OpenSSL, GnuTLS, NSS o SSH.

Cómo funciona

  1. Extrae el perfil seccomp integrado activo de Docker inspeccionando el HostConfig.SecurityOpt de un contenedor de corta duración. Esto evita cualquier dependencia de una URL remota y garantiza que el perfil base coincida con la versión de Docker realmente instalada. Una descarga de GitHub desde moby/profiles se utiliza como respaldo solo si la inspección del contenedor no produce resultados.

  2. Parchea el perfil eliminando socket de la entrada de lista blanca de Docker y re-agregándolo con un filtro de argumentos que permite todas las familias de direcciones excepto AF_ALG (valor 38) usando SCMP_CMP_NE. Todo el resto del comportamiento seccomp predeterminado de Docker se conserva.

  3. Escribe el perfil parcheado de forma atómica en /etc/seccomp/docker-block-af-alg.json (archivo temporal + renombrado). Se omite si el contenido en disco ya es idéntico.

  4. Actualiza /etc/docker/daemon.json para establecer "seccomp-profile" en la ruta del perfil parcheado. El archivo original se respalda en daemon.json.bak en la primera modificación. Se omite si ya está configurado correctamente.

  5. Recarga dockerd mediante systemctl reload docker (SIGHUP: no se requiere reinicio). Se omite si ninguno de los archivos cambió.

  6. Verifica que el bloqueo esté activo ejecutando una sonda dentro de un contenedor, independientemente de si se realizaron cambios en los pasos anteriores.

El script es idempotente: ejecutarlo varias veces produce el mismo resultado y solo recarga Docker cuando algo realmente cambió.

Nota: Los contenedores --privileged omiten todos los perfiles seccomp independientemente de esta configuración. Audite sus archivos Compose y comandos de ejecución para contenedores privilegiados por separado.

Requisitos

  • Python 3.12+
  • Docker Engine (no Docker Desktop) ejecutándose en el host
  • CLI de docker en PATH
  • curl en PATH (solo respaldo)
  • systemctl (host con systemd)
  • Root / sudo para escrituras en /etc/seccomp y /etc/docker, y para systemctl reload docker

Uso

root@kitploit:~
# Aplicar la mitigación y verificar (uso normal)
sudo python3 harden-docker-seccomp.py

# Mostrar qué cambiaría sin escribir nada ni recargar Docker
sudo python3 harden-docker-seccomp.py --dry-run

# Re-ejecutar solo la verificación del contenedor (sin cambios de configuración)
python3 harden-docker-seccomp.py --verify-only

# Salida detallada
sudo python3 harden-docker-seccomp.py --verbose

Salida esperada (primera ejecución)

root@kitploit:~
INFO Written: /etc/seccomp/docker-block-af-alg.json
INFO Updated: /etc/docker/daemon.json
INFO Reloading Docker daemon (SIGHUP)…
INFO Docker daemon reloaded.
INFO Verifying AF_ALG is blocked inside a container…
OK: AF_ALG blocked — [Errno 1] Operation not permitted
INFO All done. CVE-2026-31431 (Copy Fail) mitigation is active.

Salida esperada (ejecuciones posteriores)

root@kitploit:~
INFO Profile unchanged: /etc/seccomp/docker-block-af-alg.json
INFO daemon.json already configured correctly.
INFO No changes — Docker daemon reload not required.
INFO Verifying AF_ALG is blocked inside a container…
OK: AF_ALG blocked — [Errno 1] Operation not permitted
INFO All done. CVE-2026-31431 (Copy Fail) mitigation is active.

Códigos de salida

CódigoSignificado
0Éxito: la mitigación está activa
1El script no se ejecutó como root (al parchear), o error irrecuperable
2Falló la verificación: AF_ALG no está bloqueado

Kubernetes

Los pods de Kubernetes comparten el kernel del host, por lo que la misma primitiva de socket AF_ALG es accesible desde cualquier pod en un nodo afectado. El seccomp RuntimeDefault no es suficiente: los clústeres probados mostraron que los pods admitidos bajo PSS Restricted aún podían abrir sockets AF_ALG. Se requiere un perfil Localhost con una regla de denegación explícita.

La mitigación requiere dos cosas: el JSON del perfil presente en el sistema de archivos de cada nodo, y cada especificación de pod que lo referencie. Las secciones a continuación cubren ambas, incluyendo cómo inyectar el perfil globalmente sin modificar las especificaciones individuales de los pods.

Paso 1: Distribuir el perfil a cada nodo

El kubelet resuelve los perfiles seccomp Localhost en relación con su raíz de seccomp, que por defecto es /var/lib/kubelet/seccomp. El perfil debe existir en esa ruta en cada nodo que pueda programar una carga de trabajo.

Aplique el ConfigMap y el DaemonSet de este repositorio:

root@kitploit:~
kubectl apply -f templates/configmap-seccomp-profile.yaml
kubectl apply -f templates/daemonset-distribute-profile.yaml

El DaemonSet ejecuta un contenedor init que copia el perfil desde el ConfigMap a la raíz de seccomp del kubelet del nodo, y luego estaciona un contenedor pause mínimo para que el pod permanezca visible para el monitoreo de salud. Tolera todos los taints para que también se ejecute en nodos del plano de control.

Raíz de seccomp del kubelet no estándar: RKE2 usa /var/lib/rancher/rke2/agent/kubelet/seccomp. Sobrescriba la ruta estableciendo NODE_SECCOMP_ROOT en el entorno del contenedor init del DaemonSet antes de aplicar.

Verifique que el archivo esté presente en un nodo:

root@kitploit:~
kubectl -n kube-system exec -it \
  $(kubectl -n kube-system get pod -l app.kubernetes.io/name=distribute-af-alg-seccomp \
    -o jsonpath='{.items[0].metadata.name}') -- \
  cat /var/lib/kubelet/seccomp/block-af-alg.json

Paso 2: Inyectar el perfil en cada pod (sin cambios en las especificaciones de los pods)

En lugar de modificar las especificaciones individuales de los pods o los charts de Helm, use un webhook de admisión mutante para inyectar seccompProfile automáticamente en el momento de la admisión. Se proporcionan dos opciones: Kyverno y OPA Gatekeeper.

Ambos enfoques solo inyectan el perfil cuando un pod no declara ya uno, por lo que los pods con perfiles explícitos no se modifican.

Importante: Los pods existentes en ejecución no se mutan retroactivamente. Después de aplicar la política, reinicie sus deployments para que recojan el perfil inyectado:

root@kitploit:~
kubectl rollout restart deployment -A

Opción A: Kyverno

Esta plantilla usa la API MutatingPolicy (policies.kyverno.io/v1), que alcanzó GA en Kyverno 1.17. La API heredada ClusterPolicy (kyverno.io/v1) fue deprecada en Kyverno 1.17 (enero de 2026) y está planificada para su eliminación en 1.20 (octubre de 2026); no la use para políticas nuevas.

La expresión CEL matchConditions verifica que seccompProfile esté ausente antes de mutar, por lo que los pods que ya declaran un perfil no se modifican.

root@kitploit:~
# Instalar Kyverno (si aún no está presente)
helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update
helm upgrade --install kyverno kyverno/kyverno -n kyverno --create-namespace

# Aplicar la política
kubectl apply -f templates/kyverno-mutate-seccomp.yaml

Verifique que un pod nuevo reciba el perfil inyectado:

root@kitploit:~
kubectl run test --image=busybox --restart=Never -- sleep 30
kubectl get pod test -o jsonpath='{.spec.securityContext.seccompProfile}'
# Esperado: {"localhostProfile":"block-af-alg.json","type":"Localhost"}
kubectl delete pod test

Consulte templates/kyverno-mutate-seccomp.yaml.

Opción B: OPA Gatekeeper

El CRD de mutación Assign de Gatekeeper usa una condición pathTests para inyectar el perfil solo cuando spec.securityContext.seccompProfile no existe ya. La mutación ha sido estable desde Gatekeeper 3.10+; no se requiere ningún flag de funcionalidad.

root@kitploit:~
# Instalar Gatekeeper (si aún no está presente)
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm repo update
helm install -n gatekeeper-system gatekeeper gatekeeper/gatekeeper \
  --create-namespace

# Aplicar la mutación
kubectl apply -f templates/gatekeeper-assign-seccomp.yaml

Verifique:

root@kitploit:~
kubectl run test --image=busybox --restart=Never -- sleep 30
kubectl get pod test -o jsonpath='{.spec.securityContext.seccompProfile}'
# Esperado: {"localhostProfile":"block-af-alg.json","type":"Localhost"}
kubectl delete pod test

Consulte templates/gatekeeper-assign-seccomp.yaml.

Gatekeeper vs. Kyverno: El enfoque Assign opera a nivel de campo y requiere que el webhook de mutación de Gatekeeper esté habilitado. El MutatingPolicy de Kyverno con un matchCondition CEL maneja la condición condicional en línea. Cualquiera logra el mismo resultado: prefiera el que ya esté implementado en su clúster.

Lo que esto no cubre

Los pods con hostPID: true, hostNetwork: true o securityContext.privileged: true tienen acceso elevado que seccomp por sí solo no contiene por completo. Audite esas cargas de trabajo por separado y elimine los privilegios cuando sea posible.

Notas de diseño de las plantillas

ConfigMap como fuente de verdad. El JSON del perfil reside en configmap-seccomp-profile.yaml en lugar de estar incrustado en el DaemonSet o duplicado entre archivos. El DaemonSet lo monta y lo copia al nodo. Actualizar el perfil significa editar un ConfigMap y reiniciar los pods del DaemonSet: ningún otro archivo cambia.

El DaemonSet usa prioridad system-node-critical. Esto garantiza que el pod de distribución no sea desalojado antes de que se programen las cargas de trabajo que protege, lo que dejaría nodos con un archivo de perfil faltante y pods atascados en CreateContainerError.

Gatekeeper excluye kube-system y gatekeeper-system. Inyectar un perfil Localhost en pods del sistema que pueden ser anteriores a la instalación del DaemonSet conlleva el riesgo de una referencia de perfil rota si el archivo aún no está presente en el nodo. La política de Kyverno no necesita esta exclusión porque Kyverno maneja el ordenamiento de webhooks de manera más elegante, pero las reglas exclude también se pueden agregar allí si es necesario.

Inyección condicional, no sobrescritura. Tanto el matchCondition CEL del MutatingPolicy de Kyverno como la prueba de ruta MustNotExist de Gatekeeper significan que la política de admisión solo actúa cuando un pod no tiene un seccompProfile existente. Las cargas de trabajo que ya declaran su propio perfil, incluidas aquellas que legítimamente necesitan AF_ALG mediante una lista blanca personalizada, no se modifican.

Referencias

  • https://copy.fail — Aviso del investigador original (Xint)
  • https://cert.europa.eu/publications/security-advisories/2026-005/ — Aviso de CERT-EU
  • https://www.cve.org/CVERecord?id=CVE-2026-31431 — Registro CVE
  • https://security-tracker.debian.org/tracker/CVE-2026-31431 — Rastreador de seguridad de Debian
  • https://docs.docker.com/engine/security/seccomp/ — Documentación de seccomp de Docker
  • https://github.com/moby/profiles — Perfil seccomp predeterminado canónico de Docker
  • https://kyverno.io/docs/kyverno-policies/ — Documentación de políticas de Kyverno
  • https://open-policy-agent.github.io/gatekeeper/website/docs/mutation/ — Documentación de mutación de Gatekeeper

Sí, Claude hizo la mayor parte del trabajo, aquí está el chat

https://gist.github.com/devstuff/3ff3ca0139e2a2da7f1ee5875802f76f

Descargar herramienta