
DaemonSet para mitigar la vulnerabilidad CVE-2026-64564 (SCTPhantom)
Aplicación automática de la mitigación para la vulnerabilidad CVE-2026-64564 (SCTPhantom) en el kernel de Linux en todos los worker nodes del clúster Yandex Managed Kubernetes.
Identificador CVE (CVE ID): CVE-2026-64564
Enlace CVE: https://nvd.nist.gov/vuln/detail/CVE-2026-64564
Informe original:
9b2854f86f0b en net/sctp/sm_make_chunk.cBreve descripción:
SCTPhantom es un use-after-free en el subsistema SCTP Dynamic Address Reconfiguration (ASCONF, RFC 5061) del kernel de Linux que permite a un usuario local no privilegiado obtener privilegios de superusuario (root).
La causa raíz es una discrepancia de identidades al procesar el chunk ASCONF: la verificación de la operación DEL-IP se realiza contra la dirección de origen del paquete IPv4 (S), mientras que el procesamiento posterior utiliza el transport seleccionado mediante el Address Parameter (L). Debido a esto, la secuencia ordenada
[ Address Parameter L ] [ DEL-IP L ] [ DEL-IP 0.0.0.0 ]
supera la verificación y elimina transport(L), tras lo cual la operación wildcard DEL-IP 0.0.0.0 reutiliza el puntero ya liberado como «ruta conservada». Como resultado, asoc->peer.primary_path y asoc->peer.active_path quedan como punteros colgantes al struct sctp_transport liberado, y la posterior llamada a getsockopt(SCTP_STATUS) los desreferencia.
La lógica vulnerable se introdujo en Linux 2.6.25 (año 2007, commit 42e30bf3463c), es decir, está presente en el kernel desde hace unos 18 años.
Ataque:
CAP_NET_ADMIN ni CAP_SYS_ADMIN; funciona con el perfil seccomp predeterminado activo; ASCONF y AUTH se habilitan por socket mediante SCTP_ASCONF_SUPPORTED / SCTP_AUTH_SUPPORTED, por lo que no es necesario cambiar el sysctl net.sctp.addip_enablecall_usermodehelper_exec(), que lanza un proceso en los namespaces iniciales del hostkernel panic, lo que dificulta la deteccióncommit_creds() orientado a datos), sin shellcode ni ROP clásicoTecnologías afectadas:
net/sctp (módulo sctp), procesamiento de ASCONF en net/sctp/sm_make_chunk.csctp_diag (depende de sctp) se utiliza para inspeccionar sockets SCTPLa vulnerabilidad solo es explotable si SCTP está disponible: si el módulo sctp no está cargado y su autocarga está bloqueada, el vector no está disponible.
Objetivos confirmados por los autores (se obtuvo root):
| Distribución | Kernel |
|---|
Versiones del kernel corregidas:
Los kernels de proveedor pueden contener un backport del fix incluso con una versión más antigua en la cadena de versión; la propia versión del kernel no es un indicador suficiente de vulnerabilidad; consulte el advisory o las fuentes del proveedor.
Vector de ataque y nivel de peligro según CVSS v.4.0:
Puntuación base: 8.5 (HIGH)
Vector: CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
El DaemonSet automáticamente, en cada worker node del clúster:
sctp y sctp_diag están cargados y con qué refcnt. La comprobación es deliberadamente pasiva: el DaemonSet no abre un socket SCTP antes de establecer la blacklist, para no provocar la autocarga del módulo en un nodo donde aún no está cargadorefcnt del módulo y las entradas vivas en /proc/net/sctp/assocs y /proc/net/sctp/eps. Kubernetes en sí no usa SCTP, pero las cargas de trabajo de usuario pueden declarar protocol: SCTP en Service/Pod/etc/modprobe.d/blacklist-sctp.conf con reglas install y blacklist para sctp y sctp_diagLa mitigación consta de dos partes independientes y en algunos nodos solo se aplica una de ellas.
1. Blacklist (se aplica siempre, de forma fiable). Tras crear /etc/modprobe.d/blacklist-sctp.conf, el módulo sctp ya no puede cargarse, ni automáticamente con socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP), ni mediante modprobe explícito. Esto cierra el vector en los nodos donde el módulo aún no se había cargado (estado típico: SCTP no lo usa Kubernetes y solo se carga bajo demanda).
2. Descarga del módulo de memoria (no siempre es posible). Si sctp ya estaba cargado, en la mayoría de los casos no se podrá descargar. En los nodos probados de Yandex Managed Kubernetes (Ubuntu 22.04, kernel 5.15.0-181-generic), el módulo sctp recién cargado y no utilizado por nadie ya tiene refcnt=6 con una lista de holders vacía y /proc/net/sctp/{assocs,eps} vacíos, y rmmod devuelve ERROR: Module sctp is in use. El contador no disminuye con el tiempo.
De aquí se derivan dos consecuencias:
refcnt no es un indicador de uso de SCTP: el DaemonSet lo muestra solo con fines informativos y decide la descarga basándose en las entradas vivas en /proc/net/sctp/assocs y /proc/net/sctp/epssctp ya es residente, el DaemonSet informa honestamente ⚠ mitigation applied PARTIALLY. Allí ya está la blacklist (tras un reinicio el módulo no volverá), pero hasta el reinicio el nodo sigue siendo vulnerable. Para cerrar el vector por completo, estos nodos deben reiniciarse o debe recrearse el node groupPara encontrar estos nodos tras el despliegue:
kubectl logs -n kube-system -l app=cve-2026-64564-fix -c apply-fix --prefix | grep -E 'PARTIALLY|STILL LOADED'
Importante: la mitigación desactiva SCTP por completo en el nodo.
Kubernetes y los plugins de red (Cilium, Calico) no usan SCTP para su propio funcionamiento, por lo que la mitigación es segura para la gran mayoría de los clústeres. Sin embargo, si en el clúster hay cargas que usan SCTP (por ejemplo, aplicaciones de telecomunicaciones, VoIP/señalización SS7/Diameter, Service o NetworkPolicy con protocol: SCTP), su tráfico dejará de funcionar.
Para comprobar si existen tales objetos en el clúster antes del despliegue:
# Service / Pod с protocol: SCTP
kubectl get svc -A -o json | jq -r '.items[] | select(.spec.ports[]?.protocol=="SCTP") | "\(.metadata.namespace)/\(.metadata.name)"'
kubectl get pods -A -o json | jq -r '.items[] | select(.spec.containers[].ports[]?.protocol=="SCTP") | "\(.metadata.namespace)/\(.metadata.name)"'
# NetworkPolicy с protocol: SCTP
kubectl get netpol -A -o json | jq -r '.items[] | select((.spec.ingress[]?.ports[]?.protocol=="SCTP") or (.spec.egress[]?.ports[]?.protocol=="SCTP")) | "\(.metadata.namespace)/\(.metadata.name)"'
Si SCTP se usa en el nodo, el DaemonSet por defecto no descarga el módulo de memoria, solo aplica la blacklist (el módulo no volverá tras reiniciar el nodo) y escribe una advertencia en los logs. Para forzar la descarga, cortando las conexiones SCTP existentes, establezca en el manifiesto:
env:
- name: FORCE_APPLY
value: "true"
wget https://raw.githubusercontent.com/yandex-cloud-examples/yc-mk8s-sctphantom-mitigation/main/sctphantom-mitigation-daemonset.yaml
O clonar el repositorio:
git clone https://github.com/yandex-cloud-examples/yc-mk8s-sctphantom-mitigation.git
cd yc-mk8s-sctphantom-mitigation
kubectl apply -f sctphantom-mitigation-daemonset.yaml
# Проверить статус DaemonSet
kubectl get daemonset -n kube-system cve-2026-64564-fix
# Посмотреть на скольких нодах применен фикс
kubectl get pods -n kube-system -l app=cve-2026-64564-fix -o wide
# Логи initContainer (применение фикса)
kubectl logs -n kube-system -l app=cve-2026-64564-fix -c apply-fix
# Логи основного контейнера (мониторинг)
kubectl logs -n kube-system -l app=cve-2026-64564-fix -c monitor
kubectl logs -n kube-system -l app=cve-2026-64564-fix -c apply-fix --prefix | grep -E 'PARTIALLY|STILL LOADED|Skipping'
=========================================
SCTPhantom (CVE-2026-64564) mitigation for Yandex Managed K8s
Node: demo-ru-central1-a-1
Date: Mon Aug 10 14:00:00 UTC 2026
FORCE_APPLY: false
=========================================
Step 1: Checking modules state before fix...
[LOADED] sctp (refcnt=0) - node is exposed
[UNLOADED] sctp_diag
Step 2: Checking whether SCTP is in use on this node...
✓ No SCTP usage detected (expected: Kubernetes itself does not use SCTP)
Step 3: Applying the mitigation...
Created /etc/modprobe.d/blacklist-sctp.conf
Step 4: Unloading vulnerable modules...
sctp_diag was not loaded (OK)
sctp unloaded
Step 5: Validating the configuration...
Configuration file is in place:
install sctp /bin/false
install sctp_diag /bin/false
blacklist sctp
blacklist sctp_diag
Step 6: Validating that the modules can no longer be loaded...
modprobe sctp_diag is blocked ✓
modprobe sctp is blocked ✓
SCTP socket creation is blocked ✓
Step 7: Validating modules state after fix...
[UNLOADED] sctp_diag ✓
[UNLOADED] sctp ✓
=========================================
✓ CVE-2026-64564 mitigation applied successfully
=========================================
Step 1: Checking modules state before fix...
[UNLOADED] sctp_diag
[LOADED] sctp (refcnt=6) - node is exposed
Step 2: Checking whether SCTP is in use on this node...
sctp is loaded, refcnt=6 (informational only)
✓ No SCTP usage detected (expected: Kubernetes itself does not use SCTP)
Step 4: Unloading vulnerable modules...
sctp_diag was not loaded (OK)
⚠ could not unload sctp (see the note about refcnt below)
Step 6: Validating that the modules can no longer be loaded...
modprobe sctp_diag is blocked ✓
sctp is still resident, skipping the modprobe test
⚠ SCTP socket still available: the sctp module is still resident and could not be unloaded
Step 7: Validating modules state after fix...
[UNLOADED] sctp_diag ✓
[STILL LOADED] sctp (refcnt=6) - WARNING: module could not be unloaded
=========================================
⚠ CVE-2026-64564 mitigation applied PARTIALLY
...
In that case reboot the node or recreate the node group to close the vector.
=========================================
Ese nodo debe reiniciarse: la blacklist ya impedirá que el módulo se cargue de nuevo.
La comprobación más demostrativa es reproducir la posición del atacante: un pod no privilegiado con capabilities eliminadas, como en la cadena de container escape.
NODE=<имя ноды>
kubectl run sctp-check --rm -i --restart=Never --image=python:3-slim \
--overrides="{\"spec\":{\"nodeName\":\"$NODE\",\"containers\":[{\"name\":\"c\",\"image\":\"python:3-slim\",\"securityContext\":{\"allowPrivilegeEscalation\":false,\"capabilities\":{\"drop\":[\"ALL\"]}},\"command\":[\"python3\",\"-c\",\"import socket\ntry:\n socket.socket(socket.AF_INET, socket.SOCK_STREAM, 132).close()\n print('SCTP REACHABLE -> EXPLOITABLE')\nexcept OSError as e:\n print('SCTP BLOCKED:', e)\"]}]}}"
Salida esperada en un nodo protegido:
SCTP BLOCKED: [Errno 93] Protocol not supported
En un nodo no protegido la salida será SCTP REACHABLE -> EXPLOITABLE, y la propia comprobación provocará la autocarga del módulo sctp en ese nodo (tras lo cual probablemente ya no podrá descargarse; consulte la sección anterior). No la ejecute en nodos no protegidos sin necesidad.
Puede verificar manualmente el estado del nodo. Conéctese al nodo por SSH y ejecute:
# Загружены ли уязвимые модули
lsmod | grep -E '^sctp'
# sctp 447488 0 <- refcount 0, можно выгружать
# Доступен ли SCTP-сокет (основной вектор автозагрузки модуля)
python3 -c 'import socket; socket.socket(socket.AF_INET, socket.SOCK_STREAM, 132); print("SCTP available - VULNERABLE")'
# Если выводит "SCTP available - VULNERABLE" - система уязвима
# Если выдает ошибку - система защищена
Atención: ejecutar esta comprobación en un nodo donde el módulo aún no está cargado provocará por sí misma su autocarga. Ejecútela solo después de aplicar la mitigación o de forma deliberada.
Verificar la configuración:
# Проверить наличие конфигурации блокировки
cat /etc/modprobe.d/blacklist-sctp.conf
# Ожидаемый вывод:
# install sctp /bin/false
# install sctp_diag /bin/false
# blacklist sctp
# blacklist sctp_diag
Verificar que los módulos vulnerables no estén cargados:
lsmod | grep -cE '^sctp'
# Ожидаемый вывод: 0
Si necesita aplicar la mitigación en hosts normales, una sola línea:
sudo sh -c 'printf "install sctp /bin/false\ninstall sctp_diag /bin/false\nblacklist sctp\nblacklist sctp_diag\n" > /etc/modprobe.d/blacklist-sctp.conf; rmmod sctp_diag 2>/dev/null; rmmod sctp 2>/dev/null; if lsmod | grep -qE "^sctp "; then echo "STILL-LOADED refcnt=$(cat /sys/module/sctp/refcnt)"; else echo "UNLOADED-OK"; fi'
Si es necesario eliminar el DaemonSet:
kubectl delete -f sctphantom-mitigation-daemonset.yaml
Importante: eliminar el DaemonSet no eliminará los archivos de configuración de los nodos. El archivo /etc/modprobe.d/blacklist-sctp.conf permanecerá en su lugar y seguirá protegiendo el sistema.
Para eliminar por completo el fix de los nodos, debe conectarse a cada nodo por SSH y eliminar manualmente el archivo:
rm /etc/modprobe.d/blacklist-sctp.conf
Permisos utilizados:
hostPID: true - para acceder a los procesos del host mediante nsenterprivileged: true - para escribir en /etc y descargar módulos del kernel/ - para acceder al sistema de archivos del hostImagen: ubuntu:22.04
Recursos:
Namespace: kube-system
Por qué en la configuración están tanto install como blacklist: blacklist bloquea la carga por alias (incluida la autocarga con socket(..., IPPROTO_SCTP)), pero no impide un modprobe sctp explícito. La línea install sctp /bin/false cierra también esa vía.
Por qué la mitigación no sustituye a la actualización del kernel: bloquear el módulo elimina el vector, pero el bug en sí permanece en el kernel. La solución permanente es actualizar el kernel a una versión corregida (consulte la tabla anterior) o actualizar las imágenes de los nodos y recrear el node group.
Apache License 2.0
Consulte LICENSE para más detalles.
Si tiene problemas, cree un issue en el repositorio.
| Research kernel | Linux 7.2-rc2 |
| OpenCloudOS-family | 6.6.119 |
| Debian 13 | 6.12.95+deb13-amd64 |
| Rocky Linux 9 / RHEL 9 | 5.14 vendor kernel (con el módulo sctp cargado) |
| Ubuntu 24.04 | 6.8.0-134-generic |
| Rama | Primera versión corregida | Fix estable |
|---|
| 6.6.y | 6.6.148 | fedeb4468987 |
| 6.12.y | 6.12.101 | 74e8f3e7114f |
| 6.18.y | 6.18.42 | 85aca407c560 |
| 7.1.y | 7.1.6 | d136b29bf91d |
| mainline | 7.2-rc5 | 9b2854f86f0b |
rmmod para sctp_diag y luego sctp (el orden es importante: sctp_diag depende de sctp). Si se detectan conexiones SCTP vivas, se omite la descarga a menos que se establezca explícitamente FORCE_APPLY=truemodprobe sctp sea rechazado y que la creación de un socket SCTP (socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP)) ya no sea posible