自动为 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 | 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 |
供应商内核可能以较旧版本号包含修复的 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 执行 rmmod,再对 sctp 执行(顺序很重要:sctp_diag 依赖 sctp)。如果检测到活动的 SCTP 连接,则跳过卸载,除非显式设置了 FORCE_APPLY=truemodprobe sctp 是否被拒绝,以及创建 SCTP socket(socket(AF_INET, SOCK_STREAM, IPPROTO_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)