
DaemonSet para mitigação da vulnerabilidade CVE-2026-64564 (SCTPhantom)
Aplicação automática de mitigação para a vulnerabilidade CVE-2026-64564 (SCTPhantom) no kernel Linux em todos os worker-nodes do cluster Yandex Managed Kubernetes.
Identificador CVE (CVE ID): CVE-2026-64564
Link do CVE: https://nvd.nist.gov/vuln/detail/CVE-2026-64564
Relatório original:
9b2854f86f0b em net/sctp/sm_make_chunk.cBreve descrição:
SCTPhantom é um use-after-free no subsistema SCTP Dynamic Address Reconfiguration (ASCONF, RFC 5061) do kernel Linux que permite a um usuário local não privilegiado obter privilégios de superusuário (root).
A causa raiz é uma divergência de identidades no processamento do chunk ASCONF: a verificação da operação DEL-IP é feita contra o endereço de origem do pacote IPv4 (S), enquanto o processamento posterior usa o transport selecionado via Address Parameter (L). Por causa disso, a sequência ordenada
[ Address Parameter L ] [ DEL-IP L ] [ DEL-IP 0.0.0.0 ]
passa na verificação e remove transport(L), após o que a operação wildcard DEL-IP 0.0.0.0 reutiliza o ponteiro já liberado como um "caminho persistente". Como resultado, asoc->peer.primary_path e asoc->peer.active_path permanecem como ponteiros pendentes para o struct sctp_transport liberado, e a chamada subsequente a getsockopt(SCTP_STATUS) os desreferencia.
A lógica vulnerável foi introduzida no Linux 2.6.25 (ano de 2007, commit 42e30bf3463c), ou seja, está presente no kernel há cerca de 18 anos.
Ataque:
CAP_NET_ADMIN nem CAP_SYS_ADMIN, funciona com o perfil seccomp padrão ativo; ASCONF e AUTH são habilitados por socket via SCTP_ASCONF_SUPPORTED / SCTP_AUTH_SUPPORTED, portanto não é necessário alterar o sysctl net.sctp.addip_enablecall_usermodehelper_exec(), que executa um processo nos initial namespaces do hostkernel panic, o que dificulta a detecçãocommit_creds() orientado a dados), sem shellcode e sem ROP clássicoTecnologias afetadas:
net/sctp (módulo sctp), processamento de ASCONF em net/sctp/sm_make_chunk.csctp_diag (depende de sctp), usado para inspeção de sockets SCTPA vulnerabilidade só é explorável se o SCTP estiver disponível: se o módulo sctp não estiver carregado e seu carregamento automático estiver bloqueado, o vetor fica indisponível.
Alvos confirmados pelos autores (root obtido):
| Distribuição | Kernel |
|---|---|
| Kernel de pesquisa | Linux 7.2-rc2 |
| Família OpenCloudOS | 6.6.119 |
| Debian 13 | 6.12.95+deb13-amd64 |
| Rocky Linux 9 / RHEL 9 | kernel do fornecedor 5.14 (com o módulo sctp carregado) |
| Ubuntu 24.04 | 6.8.0-134-generic |
Versões corrigidas do kernel:
| Ramo | Primeira versão corrigida | Fix estável |
|---|---|---|
| 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 |
Kernels de fornecedores podem conter um backport do fix mesmo com uma versão mais antiga na string de versão — a versão do kernel em si não é um indicador suficiente de vulnerabilidade; baseie-se no advisory ou nos fontes do fornecedor.
Vetor de ataque e nível de gravidade de acordo com o CVSS v.4.0:
Pontuação base: 8.5 (HIGH)
Vetor: 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
O DaemonSet, automaticamente, em cada worker node do cluster:
sctp e sctp_diag estão carregados e com qual refcnt. A verificação é intencionalmente passiva: o DaemonSet não abre socket SCTP antes de aplicar a blacklist, para não provocar o carregamento automático do módulo em um nó onde ele ainda não está carregadorefcnt do módulo e as entradas ativas em /proc/net/sctp/assocs e /proc/net/sctp/eps. O próprio Kubernetes não usa SCTP, mas cargas de trabalho do usuário podem declarar protocol: SCTP em Service/Pod/etc/modprobe.d/blacklist-sctp.conf com regras install e blacklist para sctp e sctp_diagrmmod para sctp_diag e depois para sctp (a ordem é importante: sctp_diag depende de sctp). Se forem detectadas conexões SCTP ativas, o descarregamento é ignorado, a menos que FORCE_APPLY=true seja definido explicitamentemodprobe sctp é rejeitado e que a criação de socket SCTP (socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP)) não passa maisA mitigação consiste em duas partes independentes, e em parte dos nós apenas uma delas é aplicada.
1. Blacklist (aplicada sempre, de forma confiável). Após a criação de /etc/modprobe.d/blacklist-sctp.conf, o módulo sctp não pode mais ser carregado — nem automaticamente ao chamar socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP), nem por modprobe explícito. Isso fecha o vetor em nós onde o módulo ainda não foi carregado (estado típico: o SCTP não é usado pelo Kubernetes e só é carregado sob demanda).
2. Descarregamento do módulo da memória (nem sempre possível). Se o sctp já estiver carregado, na maioria dos casos não será possível descarregá-lo. Em nós testados do Yandex Managed Kubernetes (Ubuntu 22.04, kernel 5.15.0-181-generic), o módulo sctp recém-carregado e não utilizado por ninguém já apresenta refcnt=6 com lista de holders vazia e /proc/net/sctp/{assocs,eps} vazios, e o rmmod retorna ERROR: Module sctp is in use. O contador não diminui com o tempo.
Daí duas consequências:
refcnt não é um indicador de uso do SCTP — o DaemonSet o exibe apenas de forma informativa, e a decisão de descarregar é tomada com base nas entradas ativas em /proc/net/sctp/assocs e /proc/net/sctp/epssctp já está residente, o DaemonSet reporta honestamente ⚠ mitigation applied PARTIALLY. A blacklist já está aplicada ali (após a reinicialização, o módulo não voltará), mas até a reinicialização o nó permanece vulnerável. Para fechar completamente o vetor, esses nós precisam ser reiniciados ou a node group precisa ser recriadaPara encontrar esses nós após a implantação:
kubectl logs -n kube-system -l app=cve-2026-64564-fix -c apply-fix --prefix | grep -E 'PARTIALLY|STILL LOADED'
Importante: a mitigação desativa completamente o SCTP no nó.
O Kubernetes e os plugins de rede (Cilium, Calico) não usam SCTP para o próprio funcionamento, portanto, para a grande maioria dos clusters, a mitigação é segura. No entanto, se houver no cluster alguma carga de trabalho que use SCTP (por exemplo, aplicações de telecom, VoIP/sinalização SS7/Diameter, Service ou NetworkPolicy com protocol: SCTP), o tráfego dela deixará de funcionar.
Antes de implantar, verifique se existem esses objetos no cluster:
# 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)"'
Se o SCTP estiver em uso no nó, o DaemonSet, por padrão, não descarrega o módulo da memória, apenas aplica a blacklist (o módulo não voltará após a reinicialização do nó) e escreve um aviso nos logs. Para descarregar à força, interrompendo as conexões SCTP existentes, defina no manifesto:
env:
- name: FORCE_APPLY
value: "true"
wget https://raw.githubusercontent.com/yandex-cloud-examples/yc-mk8s-sctphantom-mitigation/main/sctphantom-mitigation-daemonset.yaml
Ou clonar o repositório:
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.
=========================================
Esse nó precisa ser reiniciado: a blacklist já impedirá que o módulo seja carregado novamente.
A verificação mais demonstrativa é reproduzir a posição do atacante: um pod não privilegiado com capabilities removidas, como na cadeia 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)\"]}]}}"
Saída esperada em um nó protegido:
SCTP BLOCKED: [Errno 93] Protocol not supported
Em um nó não protegido, a saída será SCTP REACHABLE -> EXPLOITABLE, e a própria verificação provocará o carregamento automático do módulo sctp nesse nó (depois disso, provavelmente não será mais possível descarregá-lo — veja a seção acima). Não execute isso em nós não protegidos sem necessidade.
Você pode verificar o estado do nó manualmente. Conecte-se ao nó via SSH e execute:
# Загружены ли уязвимые модули
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" - система уязвима
# Если выдает ошибку - система защищена
Atenção: executar essa verificação em um nó onde o módulo ainda não está carregado fará com que ele seja carregado automaticamente. Execute-a somente após aplicar a mitigação ou de forma consciente.
Verificar a configuração:
# Проверить наличие конфигурации блокировки
cat /etc/modprobe.d/blacklist-sctp.conf
# Ожидаемый вывод:
# install sctp /bin/false
# install sctp_diag /bin/false
# blacklist sctp
# blacklist sctp_diag
Verificar se os módulos vulneráveis não estão carregados:
lsmod | grep -cE '^sctp'
# Ожидаемый вывод: 0
Se for necessário aplicar a mitigação em hosts comuns, use o one-liner:
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'
Se for necessário remover o DaemonSet:
kubectl delete -f sctphantom-mitigation-daemonset.yaml
Importante: remover o DaemonSet não removerá os arquivos de configuração dos nós. O arquivo /etc/modprobe.d/blacklist-sctp.conf permanecerá no lugar e continuará protegendo o sistema.
Para remover completamente o fix dos nós, é necessário conectar-se a cada nó via SSH e remover o arquivo manualmente:
rm /etc/modprobe.d/blacklist-sctp.conf
Permissões utilizadas:
hostPID: true — para acessar os processos do host via nsenterprivileged: true — para gravar em /etc e descarregar módulos do kernel/ — para acesso ao filesystem do hostImagem: ubuntu:22.04
Recursos:
Namespace: kube-system
Por que o config contém tanto install quanto blacklist: o blacklist bloqueia o carregamento por alias (incluindo o carregamento automático ao chamar socket(..., IPPROTO_SCTP)), mas não impede um modprobe sctp explícito. A linha install sctp /bin/false fecha também esse caminho.
Por que a mitigação não substitui a atualização do kernel: o bloqueio do módulo elimina o vetor, mas o bug em si permanece no kernel. A solução definitiva é atualizar o kernel para uma versão corrigida (veja a tabela acima) ou atualizar as imagens dos nós e recriar a node group.
Apache License 2.0
Consulte LICENSE para obter detalhes.
Em caso de problemas, abra uma issue no repositório.