
DaemonSet для митигации уязвимости CVE-2026-64564 (SCTPhantom)
Автоматическое применение митигации для уязвимости CVE-2026-64564 (SCTPhantom) в Linux kernel на всех worker-нодах Yandex Managed Kubernetes кластера.
Идентификатор CVE (CVE ID): CVE-2026-64564
Ссылка на CVE: https://nvd.nist.gov/vuln/detail/CVE-2026-64564
Исходный отчет:
9b2854f86f0b в net/sctp/sm_make_chunk.cКраткое описание:
SCTPhantom - это use-after-free в подсистеме SCTP Dynamic Address Reconfiguration (ASCONF, RFC 5061) ядра Linux, позволяющий непривилегированному локальному пользователю получить права суперпользователя (root).
Корневая причина - расхождение идентичностей при обработке ASCONF-чанка: проверка операции DEL-IP выполняется против адреса источника IPv4-пакета (S), а дальнейшая обработка использует transport, выбранный через Address Parameter (L). Из-за этого упорядоченная последовательность
[ Address Parameter L ] [ DEL-IP L ] [ DEL-IP 0.0.0.0 ]
проходит проверку и удаляет transport(L), после чего wildcard-операция DEL-IP 0.0.0.0 переиспользует уже освобожденный указатель как «сохраняемый путь». В результате asoc->peer.primary_path и asoc->peer.active_path остаются висячими указателями на освобожденный struct sctp_transport, а последующий вызов getsockopt(SCTP_STATUS) разыменовывает их.
Уязвимая логика была внесена в Linux 2.6.25 (2007 год, commit 42e30bf3463c), то есть присутствует в ядре около 18 лет.
Атака:
CAP_NET_ADMIN и CAP_SYS_ADMIN, работает при активном default seccomp-профиле; ASCONF и AUTH включаются per-socket через SCTP_ASCONF_SUPPORTED / SCTP_AUTH_SUPPORTED, поэтому sysctl net.sctp.addip_enable менять не нужноcall_usermodehelper_exec(), который запускает процесс в initial namespaces хостаkernel panic, что затрудняет детектcommit_creds()), без shellcode и классического ROPЗатронутые технологии:
net/sctp (модуль sctp), обработка ASCONF в net/sctp/sm_make_chunk.csctp_diag (зависит от sctp), используется для инспекции SCTP-сокетовУязвимость эксплуатируется только при доступности SCTP: если модуль sctp не загружен и его автозагрузка заблокирована, вектор недоступен.
Подтвержденные авторами цели (получен root):
| Дистрибутив | Ядро |
|---|---|
Исправленные версии ядра:
Вендорные ядра могут содержать бэкпорт фикса при более старой версии в строке версии - сама версия ядра не является достаточным признаком уязвимости, ориентируйтесь на advisory или исходники вендора.
Вектор атаки и уровень опасности согласно CVSS v.4.0:
Базовая оценка: 8.5 (HIGH)
Вектор: 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
DaemonSet автоматически на каждой worker ноде кластера:
sctp и sctp_diag, и с каким refcnt. Проверка намеренно пассивная: DaemonSet не открывает SCTP-сокет до установки блеклиста, чтобы не спровоцировать автозагрузку модуля на ноде, где он еще не загруженrefcnt модуля и живые записи в /proc/net/sctp/assocs и /proc/net/sctp/eps. Сам Kubernetes SCTP не использует, но пользовательская нагрузка может объявлять protocol: SCTP в Service/Pod/etc/modprobe.d/blacklist-sctp.conf с правилами install и blacklist для sctp и sctp_diagМитигация состоит из двух независимых частей, и на части нод применяется только одна из них.
1. Блеклист (применяется всегда, надежно). После создания /etc/modprobe.d/blacklist-sctp.conf модуль sctp больше не может быть загружен - ни автоматически при socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP), ни явным modprobe. Это закрывает вектор на нодах, где модуль еще не был загружен (типичное состояние: SCTP не используется Kubernetes и загружается только по требованию).
2. Выгрузка модуля из памяти (не всегда возможна). Если sctp уже был загружен, выгрузить его чаще всего не получится. На проверенных нодах Yandex Managed Kubernetes (Ubuntu 22.04, ядро 5.15.0-181-generic) свежезагруженный и никем не используемый модуль sctp уже имеет refcnt=6 при пустом списке holders и пустых /proc/net/sctp/{assocs,eps}, и rmmod возвращает ERROR: Module sctp is in use. Счетчик со временем не уменьшается.
Отсюда два следствия:
refcnt не является признаком использования SCTP - DaemonSet выводит его только информационно, а решение о выгрузке принимает по живым записям в /proc/net/sctp/assocs и /proc/net/sctp/epssctp уже резидентен, DaemonSet честно сообщает ⚠ mitigation applied PARTIALLY. Блеклист там уже стоит (после перезагрузки модуль не вернется), но до перезагрузки нода остается уязвимой. Для полного закрытия вектора такие ноды нужно перезагрузить или пересоздать node groupНайти такие ноды после раскатки:
kubectl logs -n kube-system -l app=cve-2026-64564-fix -c apply-fix --prefix | grep -E 'PARTIALLY|STILL LOADED'
Важно: митигация полностью отключает SCTP на ноде.
Kubernetes и сетевые плагины (Cilium, Calico) SCTP для собственной работы не используют, поэтому для абсолютного большинства кластеров митигация безопасна. Однако если в кластере есть нагрузка, использующая SCTP (например, телеком-приложения, VoIP/сигнализация SS7/Diameter, Service или NetworkPolicy с protocol: SCTP), её трафик перестанет работать.
Проверить, есть ли такие объекты в кластере, перед раскаткой:
# 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)"'
Если SCTP на ноде используется, DaemonSet по умолчанию не выгружает модуль из памяти, а только ставит блеклист (модуль не вернется после перезагрузки ноды) и пишет предупреждение в логи. Чтобы выгрузить принудительно, оборвав существующие SCTP-соединения, установите в манифесте:
env:
- name: FORCE_APPLY
value: "true"
wget https://raw.githubusercontent.com/yandex-cloud-examples/yc-mk8s-sctphantom-mitigation/main/sctphantom-mitigation-daemonset.yaml
Или клонировать репозиторий:
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.
=========================================
Такую ноду нужно перезагрузить: блеклист уже не даст модулю загрузиться заново.
Наиболее показательная проверка - воспроизвести позицию атакующего: непривилегированный под со сброшенными capabilities, как в цепочке 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)\"]}]}}"
Ожидаемый вывод на защищенной ноде:
SCTP BLOCKED: [Errno 93] Protocol not supported
На незащищенной ноде вывод будет SCTP REACHABLE -> EXPLOITABLE, и сама проверка приведет к автозагрузке модуля sctp на этой ноде (после чего выгрузить его, скорее всего, уже не удастся - см. раздел выше). Не запускайте её на незащищенных нодах без необходимости.
Вы можете проверить состояние ноды вручную. Подключитесь к ноде по SSH и выполните:
# Загружены ли уязвимые модули
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" - система уязвима
# Если выдает ошибку - система защищена
Внимание: запуск этой проверки на ноде, где модуль еще не загружен, сам приведет к его автозагрузке. Выполняйте её только после применения митигации либо сознательно.
Проверить конфигурацию:
# Проверить наличие конфигурации блокировки
cat /etc/modprobe.d/blacklist-sctp.conf
# Ожидаемый вывод:
# install sctp /bin/false
# install sctp_diag /bin/false
# blacklist sctp
# blacklist sctp_diag
Проверить, что уязвимые модули не загружены:
lsmod | grep -cE '^sctp'
# Ожидаемый вывод: 0
Если нужно применить митигацию на обычных хостах, однострочник:
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'
Если необходимо удалить DaemonSet:
kubectl delete -f sctphantom-mitigation-daemonset.yaml
Важно: Удаление DaemonSet не удалит конфигурационные файлы с нод. Файл /etc/modprobe.d/blacklist-sctp.conf останется на месте и будет продолжать защищать систему.
Для полного удаления фикса с нод нужно подключиться к каждой ноде по SSH и вручную удалить файл:
rm /etc/modprobe.d/blacklist-sctp.conf
Используемые разрешения:
hostPID: true - для доступа к процессам хоста через nsenterprivileged: true - для записи в /etc и выгрузки модулей ядра/ - для доступа к файловой системе хостаОбраз: ubuntu:22.04
Ресурсы:
Namespace: kube-system
Почему в конфиге и install, и blacklist: blacklist блокирует загрузку по alias'у (в том числе автозагрузку при socket(..., IPPROTO_SCTP)), но не мешает явному modprobe sctp. Строка install sctp /bin/false закрывает и этот путь.
Почему митигация - не замена обновлению ядра: блокировка модуля устраняет вектор, но сам баг остается в ядре. Постоянное решение - обновление ядра до исправленной версии (см. таблицу выше) либо обновление образов нод и пересоздание node group.
Apache License 2.0
См. LICENSE для подробностей.
При возникновении проблем создайте issue в репозитории.
| 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 (при загруженном модуле sctp) |
| Ubuntu 24.04 | 6.8.0-134-generic |
| Ветка | Первая исправленная версия | Stable-фикс |
|---|
| 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 |
rmmodsctp_diagsctpsctp_diagsctpFORCE_APPLY=truemodprobe sctp отклоняется, и что создание SCTP-сокета (socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP)) больше не проходит