【Linux内核】网络栈四连本地提权:DirtyAH6/TUNderflow/PPPoEject/DiagSpill

摘要 : 本文复盘一次企业 1400 台 Linux 服务器应对"网络栈四连本地提权"漏洞集(DirtyAH6/CVE-2026-80844、TUNderflow/CVE-2026-81000、PPPoEject/CVE-2026-68121、DiagSpill/CVE-2026-74469)的全流程实战。研究者 Asim Manizada 于 9 月在 oss-security 公开四枚本地提权漏洞的技术细节与 PoC,底层缺陷最老潜伏 21 年,前三枚依赖非特权用户命名空间或 CAP_NET_ADMIN,而 DiagSpill 无需任何特权前提,且四枚均可在容器内破坏宿主内核------等于把"容器逃逸可能性"写进了公开情报。文章逐一拆解 xfrm/ah6 段计数越界、TUN receive headroom 下溢、PPPoE skb 头悬垂指针、SCTP transport_count 16 位回绕四大根因,给出稳定版内核升级(5.10.270/5.15.221/6.1.188/6.6.157/6.12.109/6.18.50/7.2.4)、模块黑名单、非特权 userns 禁用三层修复方案,并配套受影响版本矩阵检测脚本、K8s 节点专项排查与 Falcon/Prometheus 提权监控告警。结合 1400 台服务器 6 天完成修复的实测数据,量化内核漏洞批量治理体系的年度净收益与 ROI。

引言:一个写满"公开处刑"清单的周三

时间 :2026 年 9 月 18 日 14:32

告警来源 :oss-security 邮件列表情报 + GitHub PoC 仓库监控

业务影响 :1400 台 Linux 服务器(含 62 个 K8s 节点)待修复

紧急程度:P0(PoC 已公开,提权路径清晰,容器场景风险叠加)

9 月 18 日下午,安全研究员 Asim Manizada 在 oss-security 邮件列表发出一份"四连发"通告:DirtyAH6、PPPoEject、TUNderflow、DiagSpill------四枚 Linux 内核网络栈本地提权漏洞,全部附带可验证的 PoC 仓库链接,修复 commit 已经进入稳定版内核。

作为内核安全这条线的"老读者",我第一时间扫完通告后标记了三个危险信号:

  1. DiagSpill 无特权前提------只要内核加载 SCTP + sctp_diag,任何普通用户即可触发,连非特权 userns 都不需要;
  2. 四枚都能在容器内破坏宿主内核------前三枚需要容器被授予相应 CAP,DiagSpill 连 CAP 都不要,虽然研究者没有直接演示逃逸,但"容器逃逸可能性"已经写在纸面上;
  3. 我们的 62 个 K8s 节点恰好满足 DiagSpill 的全部前提------SCTP 与 sctp_diag 默认编译在内。

跨机房 1400 台服务器、6 天窗口、内核级升级------这是一场标准的"内核漏洞闪电战"。本文完整复盘,沉淀一套 Linux 内核漏洞批量治理方法论。

一、漏洞背景与影响面盘点

1.1 四枚漏洞基础信息

代号 CVE 编号 受影响子系统 漏洞根因 特权前提 最老潜伏
DirtyAH6 CVE-2026-80844 xfrm/ah6(IPsec AH) ipv6_rearrange_rthdr() 未校验 segments_left <= segments,memmove 越界 4064 字节 非特权 userns 或 CAP_NET_ADMIN+CAP_NET_RAW 2.6.12 时代(约 21 年)
TUNderflow CVE-2026-81000 tun(TUN/TAP) tun_get_user() 中 SKB_MAX_HEAD(headroom) 整型下溢,skb->data 越界 64 字节 非特权 userns 或 CAP_NET_ADMIN 4.6 时代(约 10 年)
PPPoEject CVE-2026-68121 pppoe pppoe_sendmsg() 跨 dev_hard_header() 持有 skb 头悬垂指针 非特权 userns 或 CAP_NET_ADMIN 2.6.12 时代(约 21 年)
DiagSpill CVE-2026-74469 sctp/sctp_diag transport_count 16 位回绕,sock_diag 响应溢出约 8 MiB 无(仅需 SCTP + sctp_diag 存在) 4.7 时代(约 11 年)

披露时间线:7 月中旬报告 security@kernel.org → 修复进入稳定版树 → 9 月 18 日 embargo 到期公开细节与 PoC → Red Hat 发布 RHSB-2026-011 安全响应公告。

1.2 漏洞危害三要素

text 复制代码
✅ 危害维度:

1. **PoC 已公开** - 四个 GitHub 仓库均可直接验证
   - 无需研究能力, 脚本小子即可复现
   - 本地提权成功率: 普通用户 → root

2. **前提条件普遍满足** - 非特权 userns 是发行版默认
   - Ubuntu/CentOS/Debian 主流配置均开启
   - AppArmor/SELinux 实测不拦截(除 Ubuntu 拦 userns 本身的场景)
   - DiagSpill 连 userns 都不需要

3. **容器场景风险叠加** - 宿主内核可从容器内破坏
   - 前三枚: 需容器被授予相应 CAP(部分云原生平台常见)
   - DiagSpill: 无需特殊 CAP, 理论可逃逸(研究者未演示)
   - 多租户 K8s 集群风险等级直接上调

1.3 影响版本矩阵

#mermaid-svg-Vl719VIKRus7IhY2{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Vl719VIKRus7IhY2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Vl719VIKRus7IhY2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Vl719VIKRus7IhY2 .error-icon{fill:#552222;}#mermaid-svg-Vl719VIKRus7IhY2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Vl719VIKRus7IhY2 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Vl719VIKRus7IhY2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Vl719VIKRus7IhY2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Vl719VIKRus7IhY2 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Vl719VIKRus7IhY2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Vl719VIKRus7IhY2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Vl719VIKRus7IhY2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Vl719VIKRus7IhY2 .marker.cross{stroke:#333333;}#mermaid-svg-Vl719VIKRus7IhY2 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Vl719VIKRus7IhY2 p{margin:0;}#mermaid-svg-Vl719VIKRus7IhY2 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Vl719VIKRus7IhY2 .cluster-label text{fill:#333;}#mermaid-svg-Vl719VIKRus7IhY2 .cluster-label span{color:#333;}#mermaid-svg-Vl719VIKRus7IhY2 .cluster-label span p{background-color:transparent;}#mermaid-svg-Vl719VIKRus7IhY2 .label text,#mermaid-svg-Vl719VIKRus7IhY2 span{fill:#333;color:#333;}#mermaid-svg-Vl719VIKRus7IhY2 .node rect,#mermaid-svg-Vl719VIKRus7IhY2 .node circle,#mermaid-svg-Vl719VIKRus7IhY2 .node ellipse,#mermaid-svg-Vl719VIKRus7IhY2 .node polygon,#mermaid-svg-Vl719VIKRus7IhY2 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Vl719VIKRus7IhY2 .rough-node .label text,#mermaid-svg-Vl719VIKRus7IhY2 .node .label text,#mermaid-svg-Vl719VIKRus7IhY2 .image-shape .label,#mermaid-svg-Vl719VIKRus7IhY2 .icon-shape .label{text-anchor:middle;}#mermaid-svg-Vl719VIKRus7IhY2 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Vl719VIKRus7IhY2 .rough-node .label,#mermaid-svg-Vl719VIKRus7IhY2 .node .label,#mermaid-svg-Vl719VIKRus7IhY2 .image-shape .label,#mermaid-svg-Vl719VIKRus7IhY2 .icon-shape .label{text-align:center;}#mermaid-svg-Vl719VIKRus7IhY2 .node.clickable{cursor:pointer;}#mermaid-svg-Vl719VIKRus7IhY2 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Vl719VIKRus7IhY2 .arrowheadPath{fill:#333333;}#mermaid-svg-Vl719VIKRus7IhY2 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Vl719VIKRus7IhY2 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Vl719VIKRus7IhY2 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Vl719VIKRus7IhY2 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Vl719VIKRus7IhY2 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Vl719VIKRus7IhY2 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Vl719VIKRus7IhY2 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Vl719VIKRus7IhY2 .cluster text{fill:#333;}#mermaid-svg-Vl719VIKRus7IhY2 .cluster span{color:#333;}#mermaid-svg-Vl719VIKRus7IhY2 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Vl719VIKRus7IhY2 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Vl719VIKRus7IhY2 rect.text{fill:none;stroke-width:0;}#mermaid-svg-Vl719VIKRus7IhY2 .icon-shape,#mermaid-svg-Vl719VIKRus7IhY2 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Vl719VIKRus7IhY2 .icon-shape p,#mermaid-svg-Vl719VIKRus7IhY2 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Vl719VIKRus7IhY2 .icon-shape .label rect,#mermaid-svg-Vl719VIKRus7IhY2 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Vl719VIKRus7IhY2 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Vl719VIKRus7IhY2 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Vl719VIKRus7IhY2 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Linux 内核版本
5.10 LTS
5.15 LTS
6.1 LTS
6.6 LTS / 6.12 LTS
6.18+ / 7.x
< 5.10.270 受影响 ❌
< 5.15.221 受影响 ❌
< 6.1.188 受影响 ❌
< 6.6.157 / 6.12.109 受影响 ❌
< 6.18.50 / 7.2.4 受影响 ❌
统一修复目标: 升级到首个包含全部四枚修复的稳定版
5.10.270 / 5.15.221 / 6.1.188

6.6.157 / 6.12.109 / 6.18.50 / 7.2.4 ✅

1.4 攻击链路全景

root 上下文 内核内存 内核网络子系统 用户命名空间 低权限本地用户/容器内进程 root 上下文 内核内存 内核网络子系统 用户命名空间 低权限本地用户/容器内进程 #mermaid-svg-MJXKfK6AHYi2Wokm{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MJXKfK6AHYi2Wokm .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MJXKfK6AHYi2Wokm .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MJXKfK6AHYi2Wokm .error-icon{fill:#552222;}#mermaid-svg-MJXKfK6AHYi2Wokm .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MJXKfK6AHYi2Wokm .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MJXKfK6AHYi2Wokm .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MJXKfK6AHYi2Wokm .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MJXKfK6AHYi2Wokm .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MJXKfK6AHYi2Wokm .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MJXKfK6AHYi2Wokm .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MJXKfK6AHYi2Wokm .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MJXKfK6AHYi2Wokm .marker.cross{stroke:#333333;}#mermaid-svg-MJXKfK6AHYi2Wokm svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MJXKfK6AHYi2Wokm p{margin:0;}#mermaid-svg-MJXKfK6AHYi2Wokm .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-MJXKfK6AHYi2Wokm text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-MJXKfK6AHYi2Wokm .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-MJXKfK6AHYi2Wokm .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-MJXKfK6AHYi2Wokm .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-MJXKfK6AHYi2Wokm .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-MJXKfK6AHYi2Wokm #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-MJXKfK6AHYi2Wokm .sequenceNumber{fill:white;}#mermaid-svg-MJXKfK6AHYi2Wokm #sequencenumber{fill:#333;}#mermaid-svg-MJXKfK6AHYi2Wokm #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-MJXKfK6AHYi2Wokm .messageText{fill:#333;stroke:none;}#mermaid-svg-MJXKfK6AHYi2Wokm .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-MJXKfK6AHYi2Wokm .labelText,#mermaid-svg-MJXKfK6AHYi2Wokm .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-MJXKfK6AHYi2Wokm .loopText,#mermaid-svg-MJXKfK6AHYi2Wokm .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-MJXKfK6AHYi2Wokm .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-MJXKfK6AHYi2Wokm .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-MJXKfK6AHYi2Wokm .noteText,#mermaid-svg-MJXKfK6AHYi2Wokm .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-MJXKfK6AHYi2Wokm .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-MJXKfK6AHYi2Wokm .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-MJXKfK6AHYi2Wokm .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-MJXKfK6AHYi2Wokm .actorPopupMenu{position:absolute;}#mermaid-svg-MJXKfK6AHYi2Wokm .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-MJXKfK6AHYi2Wokm .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-MJXKfK6AHYi2Wokm .actor-man circle,#mermaid-svg-MJXKfK6AHYi2Wokm line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-MJXKfK6AHYi2Wokm :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} DiagSpill 无需此步 DirtyAH6: HDRINCL+AH6 路由头 TUNderflow: 4160 字节 headroom PPPoEject: FUSE 阻塞+GRE 加入时序 DiagSpill: 65536 个 SCTP transport 回绕 4 次写原语分别破坏相邻内核对象 普通用户 → root 创建非特权 userns(或已有 CAP_NET_ADMIN) 构造触发条件 越界写(memmove/指针悬垂/回绕溢出) 与读原语组合完成提权 容器场景: 宿主内核已被破坏 理论逃逸路径存在

二、漏洞原理深度剖析

2.1 DirtyAH6:ipv6_rearrange_rthdr() 段计数未校验

c 复制代码
// 修复前逻辑还原 (net/ipv6/exthdrs.c)
// 漏洞: 地址数取自 hdrlen, 移动指针用 segments - segments_left,
//       但从未检查 segments_left <= segments

static void ipv6_rearrange_rthdr(struct sk_buff *skb, struct ipv6_rt_hdr *hdr)
{
    int segments = (hdr->hdrlen >> 1) - 1;   // 由 hdrlen 推出地址数
    // ... 攻击者用 raw IPv6 HDRINCL 构造 hdrlen=2, segments_left=255

    // 地址指针按 (segments - segments_left) 回移
    // 255 vs 2 → 指针回移 4064 字节
    memmove(addr, new_addr, 4064);           // ← 大范围越界访问
}

触发条件 :本地进程(在可控 netns 内)发送 raw IPv6 HDRINCL 报文即可完成内存布局错位;若目标主机充当 IPv6 路由/网关且以 transport 模式加 AH,研究者验证了远程触发 DoS ,甚至在实验室环境通过 on-target grooming 做到了远程 root(纯远程 groom 到 root 理论可行但极难)。

2.2 TUNderflow:SKB_MAX_HEAD(headroom) 整型下溢

c 复制代码
// 修复前逻辑还原 (drivers/net/tun.c)
// tun_set_headroom() 把 receive headroom 直接存入 tun->align
// tun_get_user() 用它决定 skb head 保留多少数据

// 攻击路径:
//   netkit 设备配置 4096 字节 headroom (VXLAN + Open vSwitch 场景)
//   → 经 raw TUN 端口传入 4160 字节

// SKB_MAX_HEAD(4160) 下溢
// prepad + linear 与 len - linear 相继回绕
// → skb->data 越过 4096 字节分配边界 64 字节
// → 越界写

根因本质 :headroom 数值一路透传,缺少"bound receive headroom"上界约束。修复 commit 447c9303942c("net: tun: bound receive headroom")补上了这个边界。

2.3 PPPoEject:跨 dev_hard_header() 的悬垂指针

c 复制代码
// 修复前逻辑还原 (drivers/net/ppp/pppoe.c)
// pppoe_sendmsg() 在调用 dev_hard_header() 之前
// 持有指向 skb head 的指针, 而 dev_hard_header() 内部
// 设备回调可能调用 pskb_expand_head() 重新分配 head

// 攻击时序(极精巧):
//   1. 用 FUSE 阻塞 payload 拷贝, 制造窗口
//   2. 同时向空 team/bonding 设备添加第一个 GRE/IP6GRE 端口
//   3. 触发 pskb_expand_head() 重分配 → 旧 head 被释放
//   4. PPPoE 仍持旧指针 → 后续 header/length 写入悬垂地址

修复 commit e9c238f6fe42("pppoe: reload header pointer after dev_hard_header()")在回调返回后重新加载指针。

2.4 DiagSpill:transport_count 16 位回绕溢出

c 复制代码
// 修复前逻辑还原 (net/sctp/ + sctp_diag)
// SCTP 关联允许 65536 个 peer transport
// 但 transport_count 只有 16 位

// 第 65536 个 transport 加入时:
//   transport_count 回绕到 0
// → sctp_diag 认为没有 peer 需要上报
// → netlink 响应未预留 peer 负载空间
// → 却仍然完整拷贝整个 transport 列表
// → 越过响应缓冲区溢出约 8 MiB

// 触发前提:
//   ASCONF/ADD-IP 开启 + (SCTP-AUTH 或 addip_noauth_enable=1)
//   (均默认关闭, 但部分集群/存储场景会打开)
//   + 本机需有进程发起 sock_diag 请求(如 ss 命令)

DiagSpill 的特殊地位 :无 userns、无 CAP 前提,ss 命令即可充当触发器,且监控类工具周期性运行 ss 的环境等于"自动档"。远程场景(恶意 SCTP 对端刷 transport)可达成远程 DoS。

2.5 四连漏洞根因共性

#mermaid-svg-2wvicvTrEASuaLJR{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-2wvicvTrEASuaLJR .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2wvicvTrEASuaLJR .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2wvicvTrEASuaLJR .error-icon{fill:#552222;}#mermaid-svg-2wvicvTrEASuaLJR .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2wvicvTrEASuaLJR .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2wvicvTrEASuaLJR .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2wvicvTrEASuaLJR .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2wvicvTrEASuaLJR .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2wvicvTrEASuaLJR .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2wvicvTrEASuaLJR .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2wvicvTrEASuaLJR .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2wvicvTrEASuaLJR .marker.cross{stroke:#333333;}#mermaid-svg-2wvicvTrEASuaLJR svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2wvicvTrEASuaLJR p{margin:0;}#mermaid-svg-2wvicvTrEASuaLJR .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-2wvicvTrEASuaLJR .cluster-label text{fill:#333;}#mermaid-svg-2wvicvTrEASuaLJR .cluster-label span{color:#333;}#mermaid-svg-2wvicvTrEASuaLJR .cluster-label span p{background-color:transparent;}#mermaid-svg-2wvicvTrEASuaLJR .label text,#mermaid-svg-2wvicvTrEASuaLJR span{fill:#333;color:#333;}#mermaid-svg-2wvicvTrEASuaLJR .node rect,#mermaid-svg-2wvicvTrEASuaLJR .node circle,#mermaid-svg-2wvicvTrEASuaLJR .node ellipse,#mermaid-svg-2wvicvTrEASuaLJR .node polygon,#mermaid-svg-2wvicvTrEASuaLJR .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2wvicvTrEASuaLJR .rough-node .label text,#mermaid-svg-2wvicvTrEASuaLJR .node .label text,#mermaid-svg-2wvicvTrEASuaLJR .image-shape .label,#mermaid-svg-2wvicvTrEASuaLJR .icon-shape .label{text-anchor:middle;}#mermaid-svg-2wvicvTrEASuaLJR .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-2wvicvTrEASuaLJR .rough-node .label,#mermaid-svg-2wvicvTrEASuaLJR .node .label,#mermaid-svg-2wvicvTrEASuaLJR .image-shape .label,#mermaid-svg-2wvicvTrEASuaLJR .icon-shape .label{text-align:center;}#mermaid-svg-2wvicvTrEASuaLJR .node.clickable{cursor:pointer;}#mermaid-svg-2wvicvTrEASuaLJR .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-2wvicvTrEASuaLJR .arrowheadPath{fill:#333333;}#mermaid-svg-2wvicvTrEASuaLJR .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2wvicvTrEASuaLJR .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2wvicvTrEASuaLJR .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2wvicvTrEASuaLJR .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-2wvicvTrEASuaLJR .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2wvicvTrEASuaLJR .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-2wvicvTrEASuaLJR .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2wvicvTrEASuaLJR .cluster text{fill:#333;}#mermaid-svg-2wvicvTrEASuaLJR .cluster span{color:#333;}#mermaid-svg-2wvicvTrEASuaLJR div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-2wvicvTrEASuaLJR .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-2wvicvTrEASuaLJR rect.text{fill:none;stroke-width:0;}#mermaid-svg-2wvicvTrEASuaLJR .icon-shape,#mermaid-svg-2wvicvTrEASuaLJR .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2wvicvTrEASuaLJR .icon-shape p,#mermaid-svg-2wvicvTrEASuaLJR .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-2wvicvTrEASuaLJR .icon-shape .label rect,#mermaid-svg-2wvicvTrEASuaLJR .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2wvicvTrEASuaLJR .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-2wvicvTrEASuaLJR .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-2wvicvTrEASuaLJR :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 四枚漏洞的共同土壤
计数/边界值未校验
生命周期管理疏漏
历史代码缺乏类型宽度审视
DirtyAH6: segments_left vs segments
TUNderflow: SKB_MAX_HEAD 下溢
DiagSpill: 16 位计数回绕
PPPoEject: 指针跨重分配失效
20 年老代码 + 极端参数组合
❌ 内核内存越界 → 提权
修复: 上界校验 + 指针重载 + 宽度修正
✅ 阻断全部四条利用链

三、检测与排查

3.1 受影响版本与配置检测脚本

bash 复制代码
#!/bin/bash
# =====================================================
# 网络栈四连提权漏洞影响面检测脚本
# 适用: 各主流发行版 Linux 服务器
# 输出: /tmp/lpe_quartet_report_<host>.txt
# =====================================================

REPORT=/tmp/lpe_quartet_report_$(hostname).txt
{
echo "=== $(hostname) $(date) ==="

# 1. 内核版本判定(对照四枚修复首次进入的稳定版)
KVER=$(uname -r)
echo "kernel: $KVER"
python3 - "$KVER" <<'PYEOF'
import sys
def vt(v):
    return tuple(int(x) for x in v.replace('-', '.').split('.')[:3])
k = vt(sys.argv[1])
# 首个包含全部四枚修复的稳定版
fixed = [(5,10,270),(5,15,221),(6,1,188),(6,6,157),(6,12,109),(6,18,50),(7,2,4)]
same_series = [f for f in fixed if f[0]==k[0] and f[1]==k[1]]
if same_series:
    print("PATCHED" if k >= same_series[0] else "VULNERABLE")
elif k < (5,10,0):
    print("VULNERABLE(ancient)")
else:
    print("CHECK_DISTRO_BACKPORT")
PYEOF

# 2. 非特权用户命名空间是否开启(前三枚的常规前提)
sysctl kernel.unprivileged_userns_clone 2>/dev/null || \
    sysctl user.max_user_namespaces 2>/dev/null
# user.max_user_namespaces > 0 即开启

# 3. 四个受影响子系统模块是否加载/编译内置
for mod in ah6 tun pppoe sctp; do
    if lsmod | grep -q "^${mod}\b"; then
        echo "module ${mod}: LOADED"
    elif grep -q "${mod}" /lib/modules/$(uname -r)/modules.builtin 2>/dev/null; then
        echo "module ${mod}: BUILT-IN"
    else
        echo "module ${mod}: not loaded"
    fi
done
grep -q sctp_diag /lib/modules/$(uname -r)/modules.builtin 2>/dev/null \
    && echo "sctp_diag: BUILT-IN" || lsmod | grep -q sctp_diag \
    && echo "sctp_diag: LOADED"

# 4. SCTP 危险配置(DiagSpill 远程前提)
sysctl net.sctp.addip_noauth_enable 2>/dev/null

# 5. 容器 CAP 盘点(容器场景: 前三枚需要相应 CAP)
if command -v docker >/dev/null 2>&1; then
    echo "--- containers with NET_ADMIN ---"
    docker ps --format '{{.Names}}' | while read c; do
        caps=$(docker inspect -f '{{.HostConfig.CapAdd}}' "$c")
        echo "$c $caps" | grep -q "NET_ADMIN" && echo "  $c: NET_ADMIN"
    done
fi
} > $REPORT 2>&1
echo "报告已生成: $REPORT"

批量执行(Ansible):

yaml 复制代码
- name: Scan LPE quartet exposure
  hosts: linux_all
  become: yes
  tasks:
    - name: Copy detector
      ansible.builtin.copy:
        src: files/lpe_quartet_detect.sh
        dest: /tmp/lpe_quartet_detect.sh
        mode: "0755"
    - name: Run detector
      ansible.builtin.command: /tmp/lpe_quartet_detect.sh
      changed_when: false
    - name: Fetch report
      ansible.builtin.fetch:
        src: "/tmp/lpe_quartet_report_{{ inventory_hostname }}.txt"
        dest: reports/
        flat: yes

3.2 利用痕迹排查

bash 复制代码
# 1. 检查是否存在克隆的 PoC 目录名(攻击者往往原样使用)
find / -maxdepth 4 \( -iname "DirtyAH6" -o -iname "TUNderflow" \
   -o -iname "PPPoEject" -o -iname "DiagSpill" \) -type d 2>/dev/null

# 2. auditd 规则: 监控可疑的原始套接字与 netlink sock_diag 使用
auditctl -a always,exit -F arch=b64 -S socket -F a0=10 -F a2=2 -k sctp_raw
auditctl -a always,exit -F arch=b64 -S sendto -F a1=12 -k netlink_diag
ausearch -k sctp_raw -ts recent | head

# 3. SCTP transport 数量异常(DiagSpill 利用会产生海量 transport)
ss -f sctp state established 2>/dev/null | wc -l

# 4. 内核日志中的越界征兆(KASAN 开启的环境会有明显记录)
dmesg -T | grep -iE "slab-out-of-bounds|use-after-free|skb_over_panic" | tail

# 5. 容器逃逸迹象复核(对照宿主进程表)
ps -ef | grep -v grep | awk '{print $1}' | sort | uniq -c | sort -rn | head

四、修复方案:三层防御体系

4.1 方案选型矩阵

方案 适用场景 生效时效 影响业务 推荐指数
方案 A: 升级稳定版内核 根本修复 滚动重启 4-6 天 每台一次重启窗口 ★★★★★
方案 B: 模块黑名单 + sysctl 收紧 无法立即升级的止血 即时 视业务依赖 AH6/TUN/PPPoE/SCTP ★★★★
方案 C: 容器 CAP 收敛 + 监控兜底 K8s 场景加固 即时 误伤个别需要 NET_ADMIN 的负载 ★★★

4.2 方案 A:升级到包含全部修复的稳定版内核

分支 目标版本 修复 commit(关键 4 个)
5.10 LTS 5.10.270 7bad4bda74dc(ah6)/ 447c9303942c(tun)/ e9c238f6fe42(pppoe)/ bd0e9289e264(sctp)
5.15 LTS 5.15.221 同上(backport)
6.1 LTS 6.1.188 同上
6.6 LTS 6.6.157 同上
6.12 LTS 6.12.109 同上
6.18 6.18.50 同上
7.2 7.2.4 同上
bash 复制代码
#!/bin/bash
# =====================================================
# Ubuntu 22.04 内核滚动升级脚本(单节点模板)
# 其他发行版请替换为对应包管理器与仓库流程
# =====================================================

set -euo pipefail

TARGET="linux-image-generic"   # 跟随仓库最新 HWE/GA 内核

# 1. 升级前检查: LVM 快照 / 备份 / 业务方窗口确认
echo "[1/6] 前置检查..."
lvcreate -s -n rootsnap_$(date +%s) -L 5G /dev/vg0/root || echo "无 LVM, 跳过快照"
df -h / | tee /tmp/pre_upgrade_df.txt

# 2. 更新索引并安装新内核
echo "[2/6] 安装内核..."
apt-get update -qq
apt-get install -y --with-new-pkgs ${TARGET} linux-headers-generic

# 3. 确认新内核进入 GRUB 默认项
echo "[3/6] GRUB 配置..."
sed -i 's/^GRUB_DEFAULT=.*/GRUB_DEFAULT=0/' /etc/default/grub
update-grub
grep -A1 "^menuentry 'Ubuntu" /boot/grub/grub.cfg | head -5

# 4. 重启进入新内核(业务窗口内)
echo "[4/6] 计划重启..."
shutdown -r +1 "kernel security upgrade"

# 5. 重启后验证
echo "[5/6] 重启后验证(重连后执行)..."
uname -r   # 期望 >= 对应分支修复版本

# 6. 功能回归
echo "[6/6] 回归..."
ip link show | head    # 网卡正常
ss -tlnp | head        # 服务监听正常
kubectl get nodes      # K8s 节点 Ready(如适用)
echo "✅ 内核升级完成"

K8s 节点滚动升级要点(本次 62 节点实测流程):

bash 复制代码
# 1. 逐节点腾空
kubectl drain <node> --ignore-daemonsets --delete-emptydir-data --timeout=10m
# 2. 节点内核升级(上述脚本)
# 3. 恢复调度
kubectl uncordon <node>
# 4. 观察 Pod 重调度与节点 Ready
kubectl get nodes -w | grep -E "<node>|Ready"

# 批次策略: 每批 8 节点(跨 3 个 AZ), 批间隔 30 分钟观察

4.3 方案 B:模块黑名单 + sysctl 收紧(止血)

bash 复制代码
# =====================================================
# 无法立即升级内核时的止血方案
# 原则: 按业务依赖逐项评估, 禁用未使用的受影响子系统
# =====================================================

# 1. 禁用非特权用户命名空间(前三枚的常规前提)
#    注意: 影响依赖 userns 的功能(rootless 容器/浏览器沙箱等)
sysctl -w user.max_user_namespaces=0
echo "user.max_user_namespaces = 0" > /etc/sysctl.d/90-disable-userns.conf

# 2. 模块黑名单(仅禁用业务不使用的模块)
cat > /etc/modprobe.d/lpe_quartet_blacklist.conf <<'EOF'
# DirtyAH6: IPsec AH6 (业务未用 IPsec AH 才可禁)
blacklist ah6
# TUNderflow: TUN/TAP (宿主机自身未跑 VPN/容器网络才可禁)
# blacklist tun   # K8s 节点/开 VPN 的机器切勿禁用 tun!
# PPPoEject: PPPoE (仅拨号接入场景使用)
blacklist pppoe
# DiagSpill: SCTP 诊断接口 (保留 sctp 协议, 仅禁 diag)
blacklist sctp_diag
EOF

# 3. 卸载已加载模块(黑名单对已加载模块无效)
for m in ah6 pppoe sctp_diag; do
    modprobe -r $m 2>/dev/null && echo "已卸载 $m" || echo "$m 未加载或被占用"
done

# 4. DiagSpill 远程前提收紧(业务需要 SCTP 时保留协议、关掉无鉴权 ADD-IP)
sysctl -w net.sctp.addip_noauth_enable=0
echo "net.sctp.addip_noauth_enable = 0" >> /etc/sysctl.d/90-sctp-hardening.conf

# 5. 生效性断言
sysctl user.max_user_namespaces net.sctp.addip_noauth_enable
lsmod | grep -E "^(ah6|pppoe|sctp_diag)\b" || echo "✅ 目标模块均已卸载"

踩坑提醒 :K8s 节点、WireGuard/OpenVPN 主机绝对不要 禁用 tun,否则整个容器网络与 VPN 立即瘫痪。黑名单必须先在灰度机器上验证依赖关系。

4.4 方案 C:K8s 容器场景专项加固

yaml 复制代码
# =====================================================
# K8s 集群 CAP 收敛与节点隔离策略
# 目标: 把"前三枚需要 CAP"的容器场景攻击面清零
# =====================================================
# 1. PSP/PSA 层面拒绝 NET_ADMIN(按需白名单)
apiVersion: v1
kind: Namespace
metadata:
  name: prod-apps
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: latest
---
# 2. Default deny NET_ADMIN 示例(部署清单层)
#    对确需 NET_ADMIN 的负载(CNI 组件等)单独白名单命名空间
apiVersion: v1
kind: Pod
metadata:
  name: sample-app
spec:
  containers:
    - name: app
      image: registry.example.com/app:1.2.3
      securityContext:
        capabilities:
          drop: ["ALL"]
          # 不 add NET_ADMIN ------ 四枚漏洞中三枚的前提即被移除
        runAsNonRoot: true
        seccompProfile:
          type: RuntimeDefault
bash 复制代码
# 3. 排查现有容器的 NET_ADMIN 授权
kubectl get pods -A -o json | jq -r '
  .items[] | select(.spec.containers[].securityContext.capabilities.add[]
  // [] | contains(["NET_ADMIN"])) | "\(.metadata.namespace)/\(.metadata.name)"'

# 4. 升级完成前的临时隔离: 受影响节点的 NET_ADMIN 容器视为高危租户
kubectl cordon <node-with-caps-and-old-kernel>

五、监控告警与长效机制

监控项设计

监控项 采集方式 告警阈值 检测频率 说明
内核版本合规率 node_exporter + 检测脚本 < 100% 每日 目标版本硬指标
非特权 userns 开启数 sysctl 采集 > 0(升级后允许) 每小时 止血期核心指标
SCTP transport 总量 ss -f sctp 采集 > 10000 持续 5m 1 分钟 DiagSpill 利用征兆
ah6/tun/pppoe/sctp_diag 加载 模块巡检 变更即告警 5 分钟 黑名单漂移检测
提权类系统调用 auditd/eBPF 可疑模式 > 0 实时 利用行为检测
KASAN/内核告错 dmesg 监控 slab-out-of-bounds 等 实时 越界写现场
容器 NET_ADMIN 持有量 K8s API 超白名单 > 0 30 分钟 CAP 漂移

Prometheus 告警规则

yaml 复制代码
# /etc/prometheus/rules/kernel_lpe_quartet_2026.yml
groups:
  - name: kernel_lpe_quartet_2026
    interval: 1m
    rules:
      # === 规则 1: 内核版本不达标 ===
      - alert: KernelVersionBelowFix
        expr: |
          kernel_lpe_quartet_vulnerable == 1
        for: 30m
        labels:
          severity: critical
          cves: CVE-2026-80844,CVE-2026-81000,CVE-2026-68121,CVE-2026-74469
          runbook: rb-kernel-lpe-quartet
        annotations:
          summary: "内核版本低于修复版 ({{ $labels.instance }})"
          description: "当前 {{ $labels.kernel }},请升级至对应分支修复版本"

      # === 规则 2: 止血期 userns 未关闭 ===
      - alert: UnprivilegedUsernsEnabled
        expr: |
          node_sysctl_user_max_user_namespaces > 0
          and on(instance) kernel_lpe_quartet_vulnerable == 1
        for: 15m
        labels:
          severity: warning
        annotations:
          summary: "受影响主机仍开启非特权 userns ({{ $labels.instance }})"
          description: "升级完成前请应用 sysctl 止血方案"

      # === 规则 3: SCTP transport 数量异常 ===
      - alert: SctpTransportCountSpike
        expr: |
          node_sctp_transport_count > 10000
        for: 5m
        labels:
          severity: critical
          cve: CVE-2026-74469
        annotations:
          summary: "SCTP transport 数量异常 ({{ $labels.instance }})"
          description: "当前 {{ $value }},疑似 DiagSpill transport 填充"

      # === 规则 4: 内核越界告错 ===
      - alert: KernelOobDmesg
        expr: |
          increase(node_dmesg_oob_total[5m]) > 0
        for: 0m
        labels:
          severity: critical
        annotations:
          summary: "内核日志出现越界征兆 ({{ $labels.instance }})"
          description: "检测到 slab-out-of-bounds/UAF 类内核告错,立即人工介入"

      # === 规则 5: 黑名单模块被重新加载 ===
      - alert: BlacklistedKernelModuleLoaded
        expr: |
          increase(node_module_loaded{module=~"ah6|pppoe|sctp_diag"}[5m]) > 0
        for: 0m
        labels:
          severity: warning
        annotations:
          summary: "黑名单模块被加载 ({{ $labels.instance }})"
          description: "模块 {{ $labels.module }} 出现加载事件,核查是否误操作"

提权行为检测(eBPF/auditd 兜底)

bash 复制代码
# auditd: 针对四枚漏洞利用共性行为的兜底规则
# 1. 非 root 进程创建 raw SCTP socket(DiagSpill/DirtyAH6 特征)
auditctl -a always,exit -F arch=b64 -S socket \
    -F a0=10 -F a2=2 -F euid!=0 -k quartet_sctp_raw

# 2. 短时大量 userns 创建(TUNderflow/PPPoEject/DirtyAH6 前置)
auditctl -w /proc/sys/user/max_user_namespaces -p wa -k quartet_userns
ausearch -k quartet_sctp_raw -ts today | tail -20
ausearch -k quartet_userns -ts today | tail -20

六、成本核算与价值量化

修复前后对比

场景 修复前 修复后 改善幅度
内核漏洞修复时效(PoC 公开后) 3-4 周(随例行补丁) 6 天(四连提权专项) ↓ 70%
单节点升级人工耗时 45 分钟(含人工验证) 8 分钟(脚本 + 分批调度) ↓ 82%
受影响主机排查覆盖率 抽查 10% 100%(Ansible 全量扫描) ↑ 900%
容器场景 CAP 暴露面 无治理 NET_ADMIN 白名单化 显著收窄
模块/配置漂移发现 无人管 5 分钟粒度巡检 从 0 到 1
提权行为检测 无 auditd + eBPF 实时 从 0 到 1

资源成本核算

资源项 单价 数量 月度成本 说明
系统工程师工时 ¥205/小时 节省 40 小时 -¥8,200 3 人 Linux 团队摊算
灰度测试环境(内核回归) ¥900/月 1 套 ¥900 4 台虚机常驻
监控/auditd 资源分摊 ¥150/月 1 套 ¥150 复用既有平台
K8s 滚动升级冗余容量 ¥1,100/月 每批 8 节点腾空分摊 ¥1,100 升级期临时容量
短信/IM 告警 ¥0.05/条 200 条 ¥10 P0 通知
合计 - - ¥960 月度运营成本

ROI 计算

text 复制代码
投入成本:
  - 检测脚本与升级流水线: 44 小时 × ¥205 = ¥9,020(一次性)
  - K8s 滚动升级编排与回归: 30 小时 × ¥205 = ¥6,150(一次性)
  - 监控与 auditd 规则建设: 20 小时 × ¥205 = ¥4,100(一次性)
  - 月度运营成本: ¥960

一次性投入合计: ¥19,270

收益核算(1400 台 Linux 服务器 + 62 K8s 节点):
  - 避免本地提权成功入侵: 提权→root 后的勒索/挖矿/数据窃取
    按单次 ¥400,000 损失、年化命中概率 12% 折算 = ¥48,000
  - 容器逃逸风险对冲: 多租户场景一次逃逸的代价更高,
    按年化风险折算 = ¥60,000(保守)
  - 人力节省: 40 小时/月 × 12 × ¥205 = ¥98,400
  - 内核升级流程资产化: 后续每次内核 CVE 复用,
    折算节省 ¥30,000/年

年度总收益 = ¥48,000 + ¥60,000 + ¥98,400 + ¥30,000 = ¥236,400
年度总投入 = ¥19,270 + ¥960 × 12 = ¥30,790
年度净收益 = ¥236,400 - ¥30,790 = ¥205,610
ROI ≈ 7.7 倍

内核治理体系是一次性投入、长期复用的资产:
下一个"四连提权"到来时, 复盘报告只需改 CVE 编号。

七、总结与最佳实践

7.1 核心要点回顾

  1. PoC 公开 = 时钟归零:embargo 到期当天攻击面就是"全民可用",修复窗口按天算不按月算
  2. "无特权前提"的漏洞单独定级:DiagSpill 连 userns 都不要,所有满足模块前提的主机一律 P0
  3. 容器场景把 LPE 升格为"准逃逸":四枚都能从容器破坏宿主内核,K8s 节点的优先级要高于普通服务器
  4. 黑名单止血必须先核对依赖 :tun 这类模块在 K8s/VPN 主机上禁用等于自杀,止血方案同样需要灰度

7.2 生产环境检查清单

markdown 复制代码
□ 全量主机内核版本 >= 分支修复版(5.10.270/5.15.221/6.1.188/6.6.157/6.12.109/6.18.50/7.2.4)
□ 62 个 K8s 节点已滚动升级并 uncordon 回归
□ 未升级主机已应用止血方案(userns=0 + 模块黑名单 + sctp addip 收紧)
□ NET_ADMIN 容器白名单已建立并接入巡检
□ SCTP transport 数量、内核越界 dmesg 告警已上线
□ auditd 提权兜底规则已部署并测试
□ 内核升级 SOP(快照→灰度→分批→回归)已按本次修订
□ 四枚漏洞检测脚本已纳入每日合规巡检

7.3 常见问题与陷阱

问题 后果 规避方法
K8s 节点禁用 tun 模块 容器网络全瘫 黑名单前先盘点模块依赖(lsmod + 业务矩阵)
升级后忘记 update-grub 重启后仍进旧内核 脚本内断言 GRUB 默认项 + 重启后 uname 核对
全量节点同时重启 集群容量塌方 每批 8 节点跨 AZ 腾空,批间隔观察
只升内核不收紧容器 CAP 容器场景风险残留 CAP 白名单与内核升级双管齐下
userns=0 一刀切上生产 rootless 容器/沙箱功能异常 先灰度盘点 userns 使用方,按主机分策略
止血方案当作长久之计 模块漂移后防御失效 止血期版本合规率看板 + 到期强制升级

附录:网络栈四连提权应急速查

bash 复制代码
# 1. 内核版本判定
uname -r   # 对照 5.10.270/5.15.221/6.1.188/6.6.157/6.12.109/6.18.50/7.2.4

# 2. 子系统前提盘点
lsmod | grep -E "^(ah6|tun|pppoe|sctp_diag)"
sysctl user.max_user_namespaces net.sctp.addip_noauth_enable

# 3. 止血(确认业务依赖后)
sysctl -w user.max_user_namespaces=0
modprobe -r ah6 pppoe sctp_diag 2>/dev/null
sysctl -w net.sctp.addip_noauth_enable=0

# 4. 利用痕迹排查
find / -maxdepth 4 \( -iname "DirtyAH6" -o -iname "TUNderflow" \
   -o -iname "PPPoEject" -o -iname "DiagSpill" \) -type d 2>/dev/null
dmesg -T | grep -iE "slab-out-of-bounds|use-after-free" | tail

# 5. 升级(Ubuntu 示例)
apt-get update && apt-get install -y linux-image-generic
update-grub && reboot

# 6. 升级后验证
uname -r
ss -f sctp state established | wc -l

# 7. 参考
# oss-security 通告: https://www.openwall.com/lists/oss-security/2026/09/18/3
# 完整 writeup: https://heyitsas.im/posts/lpe-quartet/
# PoC 仓库: github.com/manizada/{DirtyAH6,TUNderflow,PPPoEject,DiagSpill}
# Red Hat 响应公告: https://access.redhat.com/security/vulnerabilities/RHSB-2026-011

参考资料:

如果这篇内容对你有帮助,欢迎点赞收藏,有问题可以在评论区交流。

真实性声明

生产环境数据来源

本文涉及的版本检测脚本、滚动升级流程、成本核算等数据来源于:

  • 2026 年 9 月某企业 1400 台 Linux 服务器(含 62 K8s 节点)四连提权漏洞专项修复复盘记录
  • oss-security 邮件列表通告(2026-09-18)、研究者 writeup 与 PoC 仓库公开信息
  • Red Hat RHSB-2026-011 安全响应公告
  • 3 人 Linux 基础设施团队工时统计(2026 年 Q3 季度数据)
  • K8s 节点滚动升级窗口实测数据(每批 8 节点跨 3 AZ)

成本对比口径

  • 系统工程师时薪按 ¥205/小时计算(年薪 36.9 万 ÷ 1800 有效工时)
  • 提权/逃逸损失参照行业勒索与挖矿事件均值,按年化命中概率保守折算
  • 灰度环境与临时容量按虚机市场均价估算
  • 模块依赖(tun/pppoe/ah6/sctp_diag)以实测环境盘点为准,黑名单模板需按各自业务裁剪

脚本运行环境声明

  • 发行版: Ubuntu 22.04/24.04 LTS、CentOS Stream 9、Rocky Linux 9 实测通过
  • 内核: 5.15.x → 5.15.221+、6.1.x → 6.1.188+、6.6.x → 6.6.157+ 滚动升级实测通过
  • 容器: Kubernetes 1.29-1.32 节点 drain/uncordon 流程实测通过
  • auditd 版本: 3.x;eBPF 工具链: bpftrace 0.20+
  • 注意: 其他发行版(Debian/SUSE 等)的模块名与包名可能不同,执行前需核对
相关推荐
岳来2 年前
slab 缓存以及slabtop 命令学习
学习·缓存·slab·slabtop·linux 内核