SUSE Security Team Spotlight Autumn 2024
#spotlight目录
- 引言
- Keepalived 后续审查
- DKIMproxy 符号链接攻击
- 处理 MirrorCache 中的漏洞报告 (CVE-2024-49505)
- Hardinfo2 中临时文件存在的问题
- Aeon-Check 中的固定临时文件加密密钥 (CVE-2024-49506)
- SDDM D-Bus 接口后续审查
- Libcgroup 再探
- Supergfxctl D-Bus 服务
- systemd v257 Varlink IPC 的 Polkit
- 杂项
- 结论
引言
欢迎来到我们的新焦点系列第二期。通过这些帖子,我们希望让您深入了解 SUSE 安全团队在发布专门报告的主要安全发现之外的活动。秋季对于 SUSE 来说总是非常忙碌,届时会准备新的服务包发布和新产品。这也导致 SUSE 安全团队收到的审查请求数量增加。这次我们将审视各种 D-Bus 接口、Polkit 认证、临时文件处理问题、一个小型 PAM 模块和 setgid 二进制文件、systemd 中的 Varlink IPC 以及其他一些主题。
Keepalived 后续审查
在 bsc#1218688 中,我们审查了 Keepalived,这是一个用 C 编写的负载均衡软件。团队中的一位同事注意到 /tmp 中临时文件的处理方式存在可疑之处,并要求进行更深入的审查。
临时文件处理
Keepalived 中临时文件的创建方式确实有些特殊。make_tmp_filename() 辅助函数接收临时文件的基本名称,并在 $TMPDIR 中返回该文件的路径。一个使用示例是 make_tmp_filename("keepalived.json"),该函数将返回 /tmp/keepalived.json。这很容易导致不安全的临时文件创建。
在代码中,生成的文件名总是与另一个实用函数 fopen_safe() 结合使用。该函数会拦截以写入模式("w")打开文件的尝试,并在后台调用 mkostemp() 函数来安全地创建临时文件。但是,生成的文件不会直接使用,而是会被 rename() 为预期的可预测文件名。这是安全的,因为 rename() 不会跟随符号链接或以其他方式重用目标路径,而只是替换它。
D-Bus 实现
Keepalived 还实现了一个以 root 身份运行的 D-Bus 系统服务。我们的团队 多年前审查过这个组件,导致了多个 CVE 分配。因此,趁此机会再次审查当前情况似乎是个好主意。然而,我们没有发现任何问题。代码虽然不是微不足道的,但很健壮。D-Bus 方法只能由 root 调用。只有一些 D-Bus 属性可以被非特权用户访问,但它们并不敏感。
DKIMproxy 符号链接攻击
我们的团队正在监控 openSUSE Tumbleweed 中 systemd 服务的更改。其中一项更改发生在 DKIMproxy 中,并导致了 bsc#1217173。DKIMproxy 是一个专为 Postfix 邮件服务器设计的代理。它实现了 DKIM 标准,用于签名出站电子邮件或验证入站电子邮件。
该软件包的 systemd 服务不是上游源代码的一部分,而是由打包者在打包层面 在 Open Build Service 中添加的。在此服务单元中,一个 shell 脚本通过 ExecStartPre 以 root 权限执行,而实际服务则以专用服务用户和组的较低权限运行。shell 脚本在非特权用户拥有的目录中执行了简单的写入操作。因此,一旦脚本再次执行,非特权用户就可以准备符号链接攻击,导致系统任意文件覆盖。写入的内容不受攻击者控制,因此这只会造成拒绝服务的影响,而不会允许权限提升。
根据我们的经验,我们可以在此案例中观察到一些典型的模式。在接下来的部分中,我们将更详细地讨论这些。
在打包层面添加的文件
在打包层面添加的配置文件、脚本或代码等资产,引入问题的可能性会增加。其中一些原因可能包括:
- 审查此类贡献的人员较少。
- 添加这些文件的流程不像 GitHub 项目那样正式。
- 添加这些文件的打包者可能缺乏对上游项目的了解。
- 打包者可能从想要特定功能或行为但又不清楚其确切作用的其他人那里获取这些文件。
- 打包者可能从其他 Linux 发行版那里接管这些文件,并假定它们质量很高。
由于我们发现此类打包资产具有较高的风险,因此我们主动监控 Open Build Service 中对此类文件的添加和更改,以主动查找问题。
systemd 服务中的预/后脚本
当 systemd 服务具有权限分离时,我们通常会发现这类以提高权限运行的 ExecStartPre 和 ExecStartPost 脚本。这种不同安全域的混合很容易引入本地安全问题。由于这些程序通常是 shell 脚本,它们没有内置机制来安全地访问非特权用户拥有的文件(以 root 身份),这进一步增加了风险。
事后添加的权限分离
特别是在最初设计为具有完全 root 权限运行的旧软件中,权限分离有时只是事后添加的,或者是在打包层面进行的非官方下游附加。表面上看,这种设置通常似乎提供了权限分离,即一个或多个组件以非 root 帐户运行。然而,一旦非特权帐户被攻破,这种权限分离通常很容易被规避。
这种薄弱的权限分离仍然可以提供一定程度的保护,并且通常比以完全 root 运行的服务有所改进。尽管如此,缺乏稳健性意味着给管理员带来了虚假的承诺:即这些服务存在强大的权限分离。但是,纵深防御有所欠缺,安全范围可能会发生变化。因此,此类问题通常被认为值得分配 CVE。在我们团队中,我们根据问题的严重性、受影响软件的流行度等因素,酌情分配或请求 CVE。对于 DKIMproxy 而言,只能发生拒绝服务,而且该软件并不十分普及,因此我们决定不为其分配 CVE。
处理 MirrorCache 中的漏洞报告 (CVE-2024-49505)
安全研究员 Erick Fernando 私下联系我们,报告了 openSUSE MirrorCache 仓库中的一个反射型 XSS 漏洞。MirrorCache 是一个根据配置将下载请求重定向到镜像的 Web 服务器。我们在 bsc#1232341 中处理了此报告,并为其分配了 CVE-2024-49505。负责的维护者应用了修复程序,我们团队成员 Paolo Perego 验证了该补丁。
幸运的是,MirrorCache 项目不属于 SUSE 的任何官方产品或服务器端基础设施。我们再次感谢 Erick Fernando 与我们联系并报告此问题。
Hardinfo2 中临时文件存在的问题
Hardinfo2 是一个用于在 Linux 上获取硬件信息、从中创建报告以及比较不同系统进行基准测试的实用程序。Hardinfo2 已于 10 月份为 openSUSE Tumbleweed 新打包,我们在系统监控中注意到以下内容:
RPM: hardinfo2-2.1.14-1.1.x86_64.rpm on x86_64
Package: hardinfo2
Service path: /usr/lib/systemd/system/hardinfo2.service
Runs as: root:root
Exec lines:
ExecStart=/bin/sh -c "
cat /proc/iomem >/tmp/hardinfo2_iomem;
chmod a+r /tmp/hardinfo2_iomem;
cat /proc/ioports >/tmp/hardinfo2_ioports;
chmod a+r /tmp/hardinfo2_ioports;
chmod a+r /sys/firmware/dmi/tables/*;
modprobe -q spd5118;modprobe -q ee1004;modprobe -q at24 || true"
使用固定的临时文件路径立即引起了注意,因此我们创建了 bsc#1231839 来处理由此产生的问题。默认情况下,内核保护(如 protected_symlinks)可防止更严重的问题,例如覆盖系统文件,这会导致拒绝服务。即使有这些保护措施,本地用户也可以预先创建这些文件,然后 Hardinfo2 将使用其中找到的攻击者控制的数据,导致完整性遭到破坏。
此外,此逻辑还会导致信息泄露。/proc/ioports 的数据通过临时文件 /tmp/hardinfo2_ioports 使其对所有人可读。默认情况下,此信息在 openSUSE 的 /proc 中已公开。但似乎在某些系统上并非如此,因为 Hardinfo2 执行这些步骤以允许非特权进程访问 /tmp 中的数据。另一个信息泄露是 /sys/firmware/dmi/tables/* 的 chmod a+r 操作。伪文件的权限不应被系统服务以这种方式随意更改。
我们将这些问题报告给了上游,上游迅速在这些领域进行了改进。shell 代码已移到一个名为 hwinfo2_fetch_sysdata 的proper 脚本中。/tmp 中的有问题文件现在被放置在 /run/hardinfo2 的专用目录中。现在,希望使用 hardinfo2 的用户需要成为新引入的“hardinfo2”组的成员,才能访问放置在此目录中的数据。/sys 中文件的权限不再更改。
上游创建了包含这些更改的新版本 2.2.1。我们没有为此类问题请求 CVE,因为默认情况下它们可能产生的影响最大的是 Hardinfo2 本身的完整性破坏。
Aeon-Check 中的固定临时文件加密密钥 (CVE-2024-49506)
Aeon-Check 是 openSUSE Aeon 中使用的一个小型实用程序。目前它只包含一个通过 systemd 单元调用的简单 bash 脚本。该脚本可以检测 TPM 基于 LUKS 的磁盘加密设置中的一个 bug 并修复它。为此,会暂时向根 LUKS 设备添加一个额外的 LUKS 密钥槽。
keyfile=/tmp/aeon-check-keyfile
dd bs=512 count=4 if=/dev/urandom of=${keyfile} iflag=fullblock
chmod 400 ${keyfile}
<snip>
# Writing keyfile to slot 31 (end of the LUKS2 space) to avoid clashes with any customisation/extra keys
cryptsetup luksAddKey --token-only --batch-mode --new-key-slot=31 ${rootdev} ${keyfile}
用于存储临时 LUKS 密钥的临时文件在 /tmp 中有一个固定文件名。幸运的是,该脚本设置了 errexit 选项;结合 protected_regular 和 protected_symlinks 内核功能,在该路径下使用现有文件的任何不安全操作都不会成功。然而,如果没有内核保护,另一个本地用户可以预先创建此文件,并拦截或暂存用作临时 LUKS 密钥的数据。即使如此,利用的机会也很小,因为此 systemd 服务通常只在启动时运行一次,并且临时 LUKS 密钥有效的时间窗口很短。
由于 LUKS 加密是一个敏感领域,我们仍然决定为该问题分配 CVE。我们在 bsc#1228861 中处理了该问题,脚本的作者进行了一个简单的错误修复,使用了 mktemp 来安全地创建保存 LUKS 密钥数据的临时文件。
SDDM D-Bus 接口后续审查
SDDM 显示管理器 的 openSUSE 软件包已被 openSUSE Kalpa 发行版使用。这使得需要一个新的 D-Bus 服务白名单,这在 bsc#1232647 中得到了请求。sddm-kalpa 软件包是 SDDM 的一个仅限 Wayland 的版本,但软件包中使用的源代码与常规 SDDM 相同。
我们仍然利用这个机会重新审视了 SDDM 的情况。其附带的 D-Bus 服务几乎只是一个没有实现的骨架。只有一个 D-Bus 方法 SwitchToGreeter() 被实现。没有 Polkit 授权,这意味着任何用户都可以触发切换到 greeter 的逻辑。虽然这种情况不理想,但并非关键。因此,我们接受了新软件包。
Libcgroup 再探
Libcgroup 是一个用于在 Linux 系统上使用控制组的库和实用程序集。如今,systemd 负责这项工作,并且由于 libcgroup 上游已不再维护,该软件包于 2018 年从 openSUSE 中删除。我们在 bsc#1231381 中收到了重新引入 libcgroup 的请求。上游已恢复活动,并且似乎该软件包存在一些用例。
由于该软件包包含一个 setgid 二进制文件和一个 PAM 模块,我们的团队参与其中。我们还查看了主要守护进程 cgrulesengd,它以 root 身份运行。在启动时,守护进程会遍历 /proc 中的所有正在运行的进程,并根据配置将它们分配到控制组。然后设置一个 netlink 套接字,以从内核获取有关新创建的进程和 exec() 事件的信息。这些新进程也将根据配置放入控制组。
守护进程所采用的方法在设计上易受竞争条件的影响,这在 上游仓库中也有一定的文档说明。/proc/<pid> 中的条目可能会消失或更改安全范围,例如在涉及 setuid-root 二进制文件时。配置与进程的匹配是基于它们在 /proc/<pid>/status 中找到的名称以及进程的有效 uid 和 gid。我们可以设想,一个专门的本地攻击者可以通过利用竞争条件并使用 sudo 等 setuid-root 二进制文件,使 libcgroup 守护进程错误地将一个非特权进程分配给仅供特权进程使用的控制组。由于这是设计上的问题,我们没有就此可能性与上游进行沟通。尽管如此,软件包的用户应该意识到这可能会导致本地 DoS 攻击向量。
软件包中找到的 setgid 程序 cgexec 是一个简单的程序,它只将一个 IPC 请求转发给 libcgroup 守护进程,要求其将调用进程标记为“sticky”。该二进制文件需要特殊的组权限才能连接到 libcgroup 守护进程的 UNIX 域套接字。额外的权限在连接到套接字后立即被丢弃。套接字也在发送请求后立即关闭。因此,提升组权限、泄露套接字文件描述符或以其他方式影响 cgexec 进行的 IPC 通信不再是问题。
软件包附带的 PAM 模块仅实现了一个 PAM session 类型钩子。它调用 libcgroup 库将调用进程分配到适当的控制组,从而根据配置将新会话放入控制组。
Supergfxctl D-Bus 服务
Supergfxctl 是一个 D-Bus 守护进程,负责 NVIDIA 混合 GPU 系统的底层内核设置。该软件于 11 月份新打包,我们被要求在 bsc#1232776 中为其添加白名单。
这个守护进程有一些令人担忧的地方,主要是关于本地拒绝服务攻击面。例如,守护进程中存在一些有竞争条件的逻辑,用于查找并杀死所有打开了 /dev/nvidia0 的进程。D-Bus 方法允许完全控制守护进程的配置,并且默认情况下对 sudo、users、adm 和 wheel 组的所有成员都可访问。这组组的选择相当广泛,并且肯定旨在最大限度地兼容各种 Linux 发行版。这是不幸的,因为可能有一大范围的用户可以通过这种方式控制 supergfxctl 守护进程。
为了使新服务可被 openSUSE 接受,我们要求打包者将对 D-Bus 服务的访问限制为 video 组的成员。属于 video 组的用户在访问系统视频硬件方面拥有更高的特权,因此比仅 users 组更适合 supergfxctl。更好的方法是在此 D-Bus 服务中添加 Polkit 认证,但这需要上游付出更大的努力,并且目前看不到。
systemd v257 Varlink IPC 的 Polkit
我们定期审查 systemd 新版本中 D-Bus 和 Polkit 接口的添加。这次我们被要求检查 systemd-containerd、systemd-homed、systemd-networkd 和 systemd-resolved 中的一些新 Polkit 操作。有趣的是,这些守护进程都已从使用 D-Bus 迁移到使用 Varlink 进行进程间通信 (IPC)。
根据我们的经验,systemd 组件的代码质量通常很高。这些添加也不例外。所有新的 Polkit 操作都仅限于 auth_admin 授权,因此不会为非特权本地用户增加额外的攻击面。
乍一看,切换到 Varlink 在安全方面变化不大:服务中仍然有可以被客户端调用的单个方法,并且其中一些或所有方法都可以通过 Polkit 认证进行保护。然而,切换到 Varlink 需要新的粘合代码来针对 Polkit 进行授权。因此,我们深入研究了 systemd 的实现方式。
使用 D-Bus 时,使用 SystemBusName Polkit 主题,它通过 D-Bus 发送方地址标识客户端进程。这样,polkitd 就可以通过询问 dbus-daemon 客户端用于连接 D-Bus 的 UNIX 域套接字所有者的凭据来安全地识别客户端进程的凭据。
使用 Varlink 时,不再可能这样做。相反,使用 UnixProcess 主题来标识客户端。这起初让我们有些担忧,因为 UnixProcess 主题已弃用,并且经常不安全地使用。这里的问题是 polkitd 需要使用有竞争条件的逻辑来在 /proc 文件系统中按 PID 查找进程并提取其凭据。前 SUSE 安全团队成员 Sebastian Krahmer 在 2014 年 发现了这一点,并且影响了许多使用此主题实现 Polkit 操作的程序。但是,systemd 中使用此主题来认证 Varlink 方法是健壮的。客户端的凭据是从 Varlink 连接底层的 UNIX 域套接字获取的,因此通过内核获取。此外,如今还可以将 pidfd 传递给 Polkit,这允许 polkitd 以无竞争的方式对客户端进程进行操作。
由于 Polkit 粘合代码最终是没问题的,我们接受了这些更改,并在 systemd v257 中为这些添加项添加了白名单。
杂项
以下审查并没有带来太多有意义的内容,因此我们仅在此处提供一个简短列表供参考:
- GNOME 远程桌面后续审查 (bsc#1230406)。上次我们审查 GNOME 远程桌面时,我们发现了 其 D-Bus 实现中的一些问题。此后添加了一个新的 D-Bus 服务“org.gnome.RemoteDesktop.Configuration.service”,我们被要求进行审查。新服务相对较小,其所有方法都受单个 Polkit 操作“org.gnome.remotedesktop.configure-system-daemon”保护,该操作需要 Polkit
auth_admin认证。因此,系统中不应为本地非特权用户增加额外的攻击面。总的来说,GNOME 在这一领域的复杂性仍在不断增长,而且不成为 GNOME 和远程桌面协议的专家就很难对其进行全面审查。 - UPower Daemon 中的其他 D-Bus 和 Polkit 功能 (bsc#1232835)。这只是增加了一个布尔开关,用于控制电池充电阈值是否激活。本地会话中的用户无需认证即可进行操作。
- 在 kinfocenter6 中添加了“memoryinformation” D-Bus 方法 (bsc#1231659)。我们的打包者从更新的上游版本中回溯移植了此功能。此新操作允许本地会话中的用户获取
dmidecode --type 17的输出,其中包含有关系统中物理 RAM 的一些底层信息。此实现的实现很简单,我们很放心地接受了此更改。
结论
我们希望通过这篇帖子,我们能让您更深入地了解我们在 openSUSE 和 SUSE 产品日常审查工作。如果您对本文讨论的内容有任何疑问,请随时与我们联系。我们预计焦点系列的冬季刊将在大约三个月后发布。