自动为 Yandex Managed Kubernetes 集群的所有 worker 节点应用针对 Linux 内核中 CVE-2026-64564(SCTPhantom)漏洞的缓解措施。
CVE 标识符(CVE ID): CVE-2026-64564
CVE 链接: https://nvd.nist.gov/vuln/detail/CVE-2026-64564
原始报告:
9b2854f86f0b,位于 net/sctp/sm_make_chunk.c简要描述:
SCTPhantom 是 Linux 内核 SCTP Dynamic Address Reconfiguration(ASCONF,RFC 5061)子系统中的一个 use-after-free 漏洞,允许非特权本地用户获取超级用户(root)权限。
根本原因是在处理 ASCONF chunk 时存在身份不一致:DEL-IP 操作的校验是针对 IPv4 数据包源地址(S)进行的,而后续处理使用的是通过 Address Parameter(L)选择的 transport。因此,有序序列
[ Address Parameter L ] [ DEL-IP L ] [ DEL-IP 0.0.0.0 ]
能够通过校验并删除 transport(L),随后通配符操作 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,在默认 seccomp 配置文件启用时也可工作;ASCONF 和 AUTH 通过 SCTP_ASCONF_SUPPORTED / SCTP_AUTH_SUPPORTED 按 socket 启用,因此无需修改 sysctl net.sctp.addip_enablecall_usermodehelper_exec(),它会在宿主的 initial namespaces 中启动进程kernel panic,从而增加检测难度commit_creds()),无需 shellcode 和经典 ROP受影响的技术:
net/sctp 子系统(模块 sctp),net/sctp/sm_make_chunk.c 中的 ASCONF 处理sctp_diag(依赖 sctp),用于检查 SCTP socket只有在 SCTP 可用时漏洞才能被利用:如果模块 sctp 未加载且其自动加载被阻止,则攻击向量不可用。
作者确认的目标(已获得 root):
| 发行版 | 内核 |
|---|---|
| Research kernel |
已修复的内核版本:
供应商内核可能以较旧版本号包含修复的 backport(后向移植)——内核版本号本身不足以判断是否存在漏洞,请以供应商的安全公告或源码为准。
根据 CVSS v4.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 socket,以免在模块尚未加载的节点上触发其自动加载refcnt 以及 /proc/net/sctp/assocs 和 /proc/net/sctp/eps 中的活动记录。Kubernetes 本身不使用 SCTP,但用户负载可以在 Service/Pod 中声明 protocol: SCTP/etc/modprobe.d/blacklist-sctp.conf,其中包含针对 sctp 和 sctp_diag 的 install 和 blacklist 规则sctp_diag 执行 ,再对 执行(顺序很重要: 依赖 )。如果检测到活动的 SCTP 连接,则跳过卸载,除非显式设置了 缓解措施由两个独立部分组成,部分节点上只会应用其中一部分。
1. 黑名单(始终应用,可靠)。 创建 /etc/modprobe.d/blacklist-sctp.conf 后,模块 sctp 将无法再被加载——无论是通过 socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP) 自动加载,还是显式执行 modprobe。这会关闭模块尚未加载的节点上的攻击向量(典型状态:Kubernetes 不使用 SCTP,仅在需要时加载)。
2. 从内存卸载模块(并非总可行)。 如果 sctp 已经加载,通常无法卸载它。在已测的 Yandex Managed Kubernetes 节点(Ubuntu 22.04,内核 5.15.0-181-generic)上,新加载且未被任何人使用的 sctp 模块在 holders 列表为空且 /proc/net/sctp/{assocs,eps} 为空的情况下,refcnt 已经是 6,rmmod 返回 ERROR: Module sctp is in use。该计数不会随时间减少。
由此得出两个结论:
refcnt 不是 SCTP 使用情况的标志——DaemonSet 仅将其作为信息输出,而根据 /proc/net/sctp/assocs 和 /proc/net/sctp/eps 中的活动记录决定是否卸载sctp 已驻留的节点上,DaemonSet 会如实报告 ⚠ mitigation applied PARTIALLY。黑名单已经设置(重启后模块不会再次加载),但在重启之前节点仍然易受攻击。要完全关闭此攻击向量,需要重启这些节点或重新创建节点组在部署后查找此类节点:
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 信令、带有 protocol: SCTP 的 Service 或 NetworkPolicy),其流量将停止工作。
在部署前检查集群中是否存在此类对象:
# 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.
=========================================
此类节点需要重启:黑名单已能阻止模块重新加载。
最具说明性的验证是复现攻击者的位置:一个非特权 Pod,capabilities 被全部丢弃,就像容器逃逸链中那样。
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 — 用于通过 nsenter 访问宿主进程privileged: true — 用于写入 /etc 和卸载内核模块/ — 用于访问宿主文件系统镜像: ubuntu:22.04
资源:
命名空间: kube-system
为什么配置中同时包含 install 和 blacklist: blacklist 会阻止通过别名加载(包括在 socket(..., IPPROTO_SCTP) 时的自动加载),但不会阻止显式执行 modprobe sctp。install sctp /bin/false 这一行也封堵了该路径。
为什么缓解措施不能替代内核更新: 阻止模块加载虽然消除了攻击向量,但漏洞本身仍存在于内核中。长期解决方案是更新内核到已修复版本(见上表),或者更新节点镜像并重新创建节点组。
Apache License 2.0
详见 LICENSE。
如有问题,请在仓库中创建 issue。
| Linux 7.2-rc2 |
| OpenCloudOS-family | 6.6.119 |
| Debian 13 | 6.12.95+deb13-amd64 |
| Rocky Linux 9 / RHEL 9 | 5.14 供应商内核(在加载了 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 |
rmmodsctpsctp_diagsctpFORCE_APPLY=truemodprobe sctp 是否被拒绝,以及创建 SCTP socket(socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP))是否不再成功