摘要 : 本文复盘一次企业 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 已经进入稳定版内核。
作为内核安全这条线的"老读者",我第一时间扫完通告后标记了三个危险信号:
- DiagSpill 无特权前提------只要内核加载 SCTP + sctp_diag,任何普通用户即可触发,连非特权 userns 都不需要;
- 四枚都能在容器内破坏宿主内核------前三枚需要容器被授予相应 CAP,DiagSpill 连 CAP 都不要,虽然研究者没有直接演示逃逸,但"容器逃逸可能性"已经写在纸面上;
- 我们的 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 核心要点回顾
- PoC 公开 = 时钟归零:embargo 到期当天攻击面就是"全民可用",修复窗口按天算不按月算
- "无特权前提"的漏洞单独定级:DiagSpill 连 userns 都不要,所有满足模块前提的主机一律 P0
- 容器场景把 LPE 升格为"准逃逸":四枚都能从容器破坏宿主内核,K8s 节点的优先级要高于普通服务器
- 黑名单止血必须先核对依赖 :
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
参考资料:
- oss-security: A quartet of Linux local root vulns (Asim Manizada)
- 研究者完整 writeup: LPE Quartet
- PoC: DirtyAH6 / TUNderflow / PPPoEject / DiagSpill
- Red Hat RHSB-2026-011: Network Stack Privilege Escalations
- The Hacker News: Public Exploits Released for Four Linux Kernel Flaws
- Linux 稳定版内核发布
如果这篇内容对你有帮助,欢迎点赞收藏,有问题可以在评论区交流。
真实性声明
生产环境数据来源
本文涉及的版本检测脚本、滚动升级流程、成本核算等数据来源于:
- 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 等)的模块名与包名可能不同,执行前需核对