目录

1) 引言

SSSD (System Security Services Daemon) 是一套守护进程,用于基于 LDAP、Kerberos 和 FreeIPA 等机制处理用户认证。本报告基于 SSSD 版本 2.10.0。

SSSD 支持通过指定构建时配置开关 --with-sssd-user=... 来设置用户特权分离。然而,许多 Linux 发行版中的默认设置仍然是作为 root 运行 SSSD。当启用特权分离时,文件权限能力会被分配给 SSSD 提供的一组辅助二进制文件。

/usr/libexec/sssd/sssd_pam      root:sssd 0750 cap_dac_read_search=p
/usr/libexec/sssd/selinux_child root:sssd 0750 cap_chown,cap_dac_override,cap_setuid,cap_setgid=ep
/usr/libexec/sssd/krb5_child    root:sssd 0750 cap_chown,cap_dac_override,cap_setuid,cap_setgid=ep
/usr/libexec/sssd/ldap_child    root:sssd 0750 cap_chown,cap_dac_override,cap_setuid,cap_setgid=ep

只有属于专用 sssd 账户组的成员才允许执行这些特权辅助程序。在 SSSD 2.10.0 版本之前,这些辅助程序(sssd_pam 除外)拥有 setuid-root 位。通过 commit 7239dd6791,这已被更改为使用能力。

我们的 openSUSE SSSD 打包人员在更新到 2.10.0 版本的同时首次启用了特权分离。这使得特权辅助程序进入了我们的视野,我们对其进行了审查。我们发现这些辅助二进制程序目前在 SSSD 中并未提供适当的特权分离。其中一些提供了可以再次提升到 root 或获得强大能力的攻击向量。此外,SSSD 的 systemd 服务单元在特权分离激活时也存在问题。特权辅助程序并非全局可访问,因此本地用户在拥有专用 sssd 账户之外,无法立即利用。

我们于 11 月 15 日私下将以下发现报告给了 Red Hat 安全团队。在约一个月的时间内,我们进行了一次协调披露。之后,SSSD 开发人员基于以下原因认为这些问题“ 是安全问题”:

  • 这些问题不能直接利用,仅影响纵深防御。
  • 正如设计的那样,sssd 用户和组具有很高的权限,因为这些守护进程会影响认证的结果。
  • 特权分离被引入作为额外的加固措施,而不是一个强大的安全层。
  • 特权分离也被引入是为了某些美化目的:“允许在不支持/不允许在 uid=0/user-ns 下运行应用程序(如受限的 OCP 配置文件)的受限环境中运行 SSSD”。

我们认为,这些问题仍然与安全相关。例如,考虑这样一个场景:系统管理员或打包人员意外地或由于对安全的错误期望,允许系统中所有用户执行特权二进制文件。虽然拒绝全局访问特权二进制文件是常见的做法,但根据我们的经验,这通常只是作为加固措施,而不是为了防止程序中已知的弱点。尽管辅助程序的权限在 SSSD 的安装例程中得到了正确应用,但我们没有找到任何文档说明这些辅助程序是安全敏感的,并且除了 sssd 之外的其他账户不得访问它们。

我们没有积极争取分配 CVE 标识符,尽管我们认为从形式上来说它们仍然是合理的。我们认识到,即使特权辅助程序允许恢复到 root,将 SSSD 进程以非 root 用户身份运行仍然可以是一种改进。

尽管如此,上游仍在努力并继续致力于一系列修复,以解决本报告中的发现。我们在以下章节中讨论了我们发现的各个问题。

2) krb5_child 辅助程序中的问题

与大多数其他辅助程序一样,此程序接受 STDIN 上的二进制输入。krb5_child 辅助程序读取大量复杂的结构体,如 struct krb5_reqstruct pam_data。在此上下文中相关的结构体字段是 krb5_req.ccnamekrb5_req.keytab,它们指定要处理的文件路径。

ccname 字段用于代码路径 privileged_krb5_setup()k5c_ccache_setup()k5c_precreate_ccache()。这最终会进入一个循环,该循环使用同样从 STDIN 接收的 uidgid 值,创建 STDIN 指定路径的所有父目录。

这个 概念验证 展示了如何通过这种方式创建任意所有权的任意新目录。通过巧妙地创建攻击者控制下的目录,例如在查找受信任的系统二进制文件或库时使用的目录,或者在 /etc 中用于受信任配置文件或特权服务的目录,这很可能允许进行完整的本地 root 漏洞利用。

上游修复

此特定的提权路径已在 SSSD 2.10.1 错误修复版本中得到解决。鉴于此辅助程序提供的广泛接口,很可能存在进一步的此类提权向量。由于上游不认为这是一个强大的安全屏障,我们没有对此组件进行更深入的调查。

3) sssd_pam 辅助程序中的问题

此辅助程序启动一个服务器实例,该实例提供基于套接字的 IPC 接口,用于将其 PAM 操作请求传递给它。这是唯一具有更有限能力(仅 CAP_DAC_READ_SEARCH)的辅助程序,它允许覆盖任何读取访问权限检查。

在代码路径 server_setup()confdb_init() 中,以下环境变量在 ldb_init() 中被解释(ldb_init() 是 Samba 库代码的一部分)

  • LDB_MODULES_PATH
  • LDB_MODULES_ENABLE_DEEPBIND
  • TDB_NO_FSYNC

LDB_MODULES_PATH 变量允许调用者指定一个目录,通过 dlopen() 从中加载任意共享对象。这个简单的 概念验证 展示了如何利用这种情况来访问 /etc/shadow 的内容。

与其他辅助程序不同,sssd_pam 以前没有被赋予 setuid-root 位。 CAP_DAC_READ_SEARCH 是在 commit 0562646cc261 中较早添加的,以便它能够访问 keytab 而无需以 root 身份运行。

上游修复

有一个 待处理的上游拉取请求,用于清除此辅助程序的环境,以防止此特定的特权升级路径。

4) 关于 selinux_child 辅助程序的说明

我们在此辅助程序中未发现任何特定的特权升级路径。然而,此辅助程序的性质是允许修改 SELinux MLS 映射。它通过 STDIN 上的二进制协议接收任意用户名的新的 MLS 范围。在 SELinux MLS 管理的系统中,这对 SSSD 来说是一个相当强大的权限。由于这可能是设计如此,我们认为对此能做的很少,除了记录该辅助程序的敏感性以及必须严格限制对其的访问。

该辅助程序会调用共享的 SSSD 库代码以及 libsemanage 和 libselinux。幸运的是,我们没有找到任何解释过于危险的环境变量的情况(除了在 7.a 部分中列出的常见变量)。

此辅助程序在早期也会将其 UID 和 GID 更改为 0。在转换为 UID 0 时,内核不会再次将完整的能力集分配给进程。这意味着进程运行在**受限**的 root 权限下,拥有 UID 和 GID 0,但只有分配给 selinux_child 二进制文件的能力。此外,SSSD 进程运行在 systemd 加固功能 SecureBits=noroot noroot-locked 下,从而阻止该辅助程序使用 sudo 等 setuid 二进制文件来恢复完整的 root 权限。

然而,Linux 中受限 root 权限的安全性不足。Linux 内核使用能力进行权限检查,但用户空间实用程序通常仅依赖于其他进程的 UID 和 GID 凭证。此外,某些 API 缺乏表达受限 root 权限的可能性,例如在 UNIX 域套接字中,SO_PEERCRED 选项用于确定对等进程的凭证,该选项仅提供一个 struct ucred,其中包含对等进程的 PID、UID 和 GID。因此,此辅助程序以接近完全 root 的权限运行。

5) 关于 ldap_child 辅助程序的说明

除了 第 7 节中适用于此辅助程序的通用评论外,我们在该辅助程序中未发现任何重大问题。

6) sssd.service Unit 中的问题

sssd.service systemd 单元包含以下 ExecStartPre

ExecStartPre=+-/bin/chown -f -R root:@SSSD_USER@ @sssdconfdir@
ExecStartPre=+-/bin/chmod -f -R g+r @sssdconfdir@
ExecStartPre=+-/bin/sh -c "/bin/chown -f @SSSD_USER@:@SSSD_USER@ @dbpath@/*.ldb"
ExecStartPre=+-/bin/chown -f -R @SSSD_USER@:@SSSD_USER@ @gpocachepath@
ExecStartPre=+-/bin/sh -c "/bin/chown -f @SSSD_USER@:@SSSD_USER@ @logpath@/*.log"

/var/log/sssd 和 /var/lib/sssd 目录由非特权的 sssd 用户拥有。上面以 root 身份运行的 chownchmod 行允许被攻破的 sssd 用户进行符号链接攻击,从而获得特权系统文件的所有权或访问权限。

这是一个演示该问题的简单概念验证。

# stage a symlink attack to gain ownership of /etc/shadow
sssd$ cd /var/log/sssd
sssd$ ln -s /etc/shadow my.log
# as root trigger a sssd (re)start
# sssd needs to be configured (i.e. /etc/sssd & friends need to exist) for this to work
root# systemctl restart sssd.service
root# ls -lh /etc/shadow
-rw------- 1 sssd sssd 889 Nov 13 11:40 /etc/shadow

由于受此影响的目录不是全局可写且不带 sticky bit,Linux 内核的符号链接保护在此处无法奏效。在 chownchmod 的命令行上直接命名的路径参数将被跟随(如果它们是符号链接),除非传递了 --no-dereference。传递此选项也是推荐的修复方法。

我们认为这种自动权限“修复”应谨慎对待。如果这是为了避免与旧版安装(无特权分离)的迁移麻烦,那么我们宁愿提供一个供系统管理员运行的显式实用程序。这将清楚地表明该逻辑仅运行一次,而不是每次启动 sssd 时都运行。它还将防止任何配置错误持续存在或被掩盖(例如,系统中其他组件为 SSSD 文件分配了错误的权限,从而与自动权限修复相冲突)。

上游修复

有一个 待处理的上游拉取请求,用于将 --no-dreference 传递给 systemd 服务单元中找到的 chown 调用。

7) 进一步观察

7.a) 环境变量

辅助程序还解释了其他环境变量。

  • TALLOC_FREE_FILL:将导致通过 talloc_free() 释放的内存被此变量设置的字节覆盖。
  • _SSS_DOM:将影响 systemd journal 日志消息,从而允许少量日志欺骗。

虽然这些变量对程序执行只有 minor 的影响,但特权程序不应允许任意环境变量设置影响其行为。

7.b) 可转储进程属性设置

所有特权辅助程序都支持 --dumpable 命令行开关,用于控制进程是否设置 dumpable 位。此设置的默认值*是*将进程标记为可转储(SUID_DUMP_USER)。这有些出乎意料地覆盖了 sysctl 设置 fs.suid_dumpable,后者通常为 0 或 2。

进程的可转储设置是一个敏感属性,在 ptrace() 系统调用中起着重要作用,用于确定是否允许跟踪另一个进程。根据 man 2 ptrace

在一种进程可以检查另一个进程的敏感信息,或者在某些情况下修改另一个进程的状态的情况下,会执行这些检查。这些检查基于诸如两个进程的凭证和能力、目标进程是否可转储等因素。

我们认为,阻止非特权的 sssd 用户被允许跟踪特权二进制文件的唯一障碍是(进一步摘录自 man 2 ptrace):

(5.2) 如果以下任一条件不成立,则拒绝访问:- 调用者和目标进程在同一用户命名空间内,并且调用者的能力是目标进程的允许能力的超集。

通过 ptrace() 附加仅被拒绝,因为目标进程具有已提升的能力。然而,这只是一种内核安全扩展,由内核安全模块 security_ptrace_access_check() 提供。

此外,可转储设置允许非特权用户发送例如 SIGSEGV 信号到特权进程并强制它们转储核心。从这里开始会发生什么取决于系统中安装的核心转储处理程序。systemd-coredump 安全地处理此类核心转储,非特权用户无法访问它们。如果仅将 core 配置为核心模式(例如,Debian Linux 默认情况下就是这样),那么非特权用户可以通过首先切换到某个目录,启动特权进程,然后将其杀死,从而导致 core 文件在任意目录中创建。非特权用户将无法读取 core 文件,但仍然允许填充文件系统,甚至可能覆盖名为 core 的合法文件。

7.c) 调试设置

特权程序还提供了丰富的命令行设置,用于启用调试输出并将其重定向到各种位置。通常,特权程序应非常谨慎地处理泄露给调用者的信息。调试日志可能包含削弱安全功能(如堆栈溢出保护)的信息,或泄露从特权文件中读取的特权信息。

8) 建议的修复

对于特权 setuid-root 类二进制文件,应采取通常的预防措施:

  • 切换到一个安全的工作目录 (CWD)。
  • 应用一个安全的文件创建模式掩码 (umask)(这已经发生)。
  • 清除环境中所有不受信任的变量,只保留一组经过验证的变量。例如,也设置一个安全的 PATH。
  • 确保任何接口(命令行参数、STDIN 数据输入)都不能为非特权调用者提供机会,使其特权超出特权程序应有的范围。

最后一点很可能是这些程序最难实现的地方,尤其是在 krb5_child 辅助程序中,我们预计会存在更多的攻击面,例如在处理 ccachekeytab 文件时。这些文件通过不了解不受信任输入的各种 krb5 库例程在其他代码路径中进行处理。我们建议上游仔细思考所有可能的输入和代码路径,并对其进行加固。

此外,我们将剥离支持的命令行开关,或者将关键开关限制给 root 调用者,特别是影响调试和日志记录的开关,如 7.c 部分所述。

在特权升级上下文中,dumpable 设置应保持不变。

最后,我们建议清晰地记录特权分离功能可以预期的内容,以及特权辅助程序在打包时如何实现安全安装(特别是它们必须不是全局可执行的)。这已经在 2.10.1 错误修复版本的描述中实现了。

9) 其他发行版上的情况

我们查看了其他一些 Linux 发行版,发现 Fedora、Debian 和 Ubuntu 目前没有使用 SSSD 的特权分离。然而,在 Arch Linux 上,当前版本 2.10.0 与特权分离一起使用,它受到本报告中涵盖的问题的影响。上游告知我们,Fedora Linux 很快也有计划使用特权分离功能。

10) 时间线

2024-11-15 我们将这些问题报告给了 Red Hat 安全团队
2024-12-04 Red Hat 安全团队为 2)3)6)(均后来撤回)的项目分配了 3 个 CVE。已建议并同意协调发布日期 (CRD) 为 2024-12-18。
2024-12-04 SSSD 开发人员 Alexey Tikhonov 回复了报告,解释说他不认为这些发现值得分配 CVE。
2024-12-09 Red Hat 安全团队建议保留这 3 个 CVE,但认为这些问题极难利用。
2024-12-10 经过内部讨论,Red Hat 安全团队决定撤回 CVE,不认为这些发现是缺陷。
2024-12-10 上游发布了 错误修复版本 2.10.1,其中包含对问题 2) 的修复,并附带说明暗示了辅助程序在打包中使用权限的敏感性。
2024-12-13 在对是否应继续协调披露流程存在一些不确定性后,我们同意立即发布。
2024-12-13 上游创建了 一个拉取请求,其中包含进一步修复 3)6) 问题的内容。

11) 参考资料