oath-toolkit: pam_oath.so 中的权限提升 (CVE-2024-47191)
#CVE #local #PAM #symlink目录
1) 引言
oath-toolkit 包含用于管理一次性密码 (OTP) 身份验证的库和实用程序,例如作为密码身份验证的第二个因素。SUSE 同事 Fabian Vogt 联系了我们的安全团队,讨论该项目的 PAM 模块。几年前,该模块增加了一个功能,允许将 OTP 状态文件(称为 usersfile)放置在待验证用户的家目录中。Fabian 注意到 PAM 模块在用户家目录中执行不安全的文件操作。由于 PAM 堆栈通常以 root 权限运行,这很容易导致安全问题。
该功能已在 oath-toolkit 版本 2.6.7 中引入(通过 commit 60d9902b5c)。以下报告基于 2.6.11 版本的最新 oath-toolkit 发布标签。
2) 漏洞详情
PAM 模块通常使用如下的 PAM 堆栈配置行进行配置:
auth [user_unknown=ignore success=ok] pam_oath.so usersfile=${HOME}/user.oath window=20
路径组件(例如 ${HOME} 或 ${USER})的展开逻辑是引入安全问题的问题功能的一部分。
PAM 模块调用 liboath 库函数 oath_authenticate_usersfile(),该函数位于 liboath/usersfile.c 中,负责管理所有对 usersfile 的访问。权限不会被放弃,并且该函数不了解特殊的特权 PAM 上下文。函数中的所有文件访问都是天真的,并且会跟随符号链接。在 OTP 条目成功后执行的相关文件操作如下:
- 通过
fopen()打开 usersfile 以供读取(usersfile.c:470)。 - 通过
fopen()使用后缀“.lock”的文件名打开一个与 usersfile 并行的锁文件以供写入(usersfile.c:332)。 - 通过
fcntl()使用 POSIX 建议锁锁定锁文件(usersfile.c:350)。 - 通过
fopen()创建一个与旧 usersfile 并行的、后缀为“.new”的新 usersfile(usersfile.c:372)。 - 通过
fchown()将新 usersfile 的所有权更改为待验证用户(usersfile.c:394)。 - 通过
rename()将新 usersfile 重命名为旧 usersfile(usersfile.c:411)。 - 取消链接之前创建的锁文件(usersfile.c:423)。
如果这发生在以 root 权限运行的 PAM 堆栈中,并且 usersfile 位于未授权用户的家目录中,那么通过放置如下的符号链接,就可以轻松地进行 root 漏洞利用:
user$ ln -s /etc/shadow $HOME/user.oath.new
这将导致 `/etc/shadow` 被覆盖,并且其所有权将被更改为待验证用户。待验证用户可以获得完整的 root 权限。无需赢得竞争条件,也无需猜测路径名。
3) 禁运流程和上游沟通
Fabian Vogt 首先通过电子邮件联系了上游的主要作者。由于几天没有收到回复,我们在上游项目中创建了一个私有的 Gitlab 问题,并提议协调披露。没有收到回复,因此我们决定自行处理禁运和错误修复,因为我们的产品需要一个已修复的 `pam_oath` 模块。我们开发了一个全面的补丁,如下节 4) 所述。
我们向 Mitre 请求了该漏洞的 CVE,他们分配了 CVE-2024-47191。
在我们准备公开漏洞时,上游作者通过私人渠道收到了通知,并对我们的报告做出了回应,准备发布一个修复该问题的上游错误修复版本,如下节 5) 所述。
由于时间限制,我们决定暂时将 SUSE 的错误修复应用到我们的产品中,直到我们能更深入地评估上游解决方案。
4) SUSE 错误修复
我们在 SUSE 内部开发了一个补丁来解决这个问题(请注意,现在有一个改进版本的补丁可用)。这个错误修复的情况比乍一看要复杂,因为当前源代码中很多地方不清楚或存在问题:
- PAM 模块无法确定目标 usersfile 应该由 root、待验证用户还是某个不相关的用户拥有。存在 `${HOME}` 路径元素表明待验证用户应该拥有该文件。然而,` ${USER}` 元素的存在并不那么清楚。
- 当前源代码中使用的锁定机制已损坏。
- usersfile 最初是在未持有锁的情况下打开进行读取和解析的(usersfile.c:470)。一个并行任务可能正在用新版本替换此文件,因此可能会发生丢失更新。
- 在 usersfile 更新后,锁文件再次被取消链接(usersfile.c:423)。这会在另一个任务等待已取消链接的锁文件时出错,而第三个任务到达,看到没有锁文件并创建一个新的。
- 锁文件放置在用户的家目录中,可能会弄乱它。需要考虑家目录是网络文件系统(NFS、CIFS)的情况。未授权用户也可能阻止特权 PAM 堆栈获取锁,导致本地拒绝服务。
我们决定开发一个补丁,该补丁尽可能考虑各种用例,在保持向后兼容性的同时保护所有操作。通过此补丁,使用 `*at` 系列系统调用安全地遍历 usersfile 路径。作为额外的安全措施,权限将降至 usersfile 所有者。已修复锁定机制以覆盖对 usersfile 的所有访问。代替创建单独的锁文件,直接使用 usersfile 进行锁定,避免了弄乱家目录。增加了额外的健全性检查,例如拒绝世界可写目录组件。该补丁采用了 Linux 特定的功能(例如,从 `/proc/self/fd` 链接文件),因此不再适用于非 Linux 系统。补丁说明和代码注释中包含有关此补丁中做出的各项决定的更多提示。
经过社区讨论后,补丁的改进版本
在 oss-security 邮件列表上进行了详细讨论后,识别出原始 SUSE 补丁的一些不足之处:
- 补丁缺少丢弃辅助组的逻辑,这通常会导致进程保留 root 组的成员身份。由于补丁中的权限下降仅用于加固,因此这并不关键。
- 补丁未处理潜在的硬链接攻击。硬链接攻击难以防范,因此在 SUSE 发行版上,内核 sysctl “sys.fs.protected_hardlinks” 默认激活。这样,内核就可以防止硬链接的危险使用。
为完整起见,我们提供了一个改进的补丁,解决了这两个方面。尽管补丁中采用的方法(接受目标文件的任何所有权)使得无法完全防御所有硬链接攻击场景。这一点由 Solar Designer 在 oss-security 邮件列表的讨论串中概述。
5) 上游错误修复
上游开发了一个替代解决方案,旨在更具可移植性和跨平台性。该方案未考虑我们在第 4 节中考虑的所有方面,但应足以修复本报告中描述的特定安全问题。
此修复已在 oath-toolkit 的 2.6.12 版本中发布。上游还发布了相关的安全公告。
6) 时间线
| 2024-08-08 | SUSE 的 Fabian Vogt 给上游的主要作者发了一封电子邮件,描述了这个问题。SUSE 安全团队也参与其中。 |
| 2024-08-20 | 在未收到电子邮件回复后,我们创建了一个私有 GitLab 问题,描述了该漏洞,并根据我们的披露政策提议协调披露。 |
| 2024-08-28 | SUSE 开始为该问题开发内部补丁。 |
| 2024-09-19 | 我们的内部补丁已准备好发布。我们在私有 GitLab 问题中添加了一个注释,给予最后两周的禁运期,然后我们将公开漏洞和补丁。我们还在问题中共享了当前补丁。 |
| 2024-09-19 | 我们向 Mitre 申请了该漏洞的 CVE。 |
| 2024-09-20 | Mitre 分配了 CVE-2024-47191。 |
| 2024-09-29 | 在通过私人渠道收到通知后,上游的主要作者对我们的沟通做出了回应,并开始准备一个错误修复版本。 |
| 2024-10-04 | 上游发布了包含错误修复的 2.6.12 版本。 |
7) 参考
- oath-toolkit 仓库
- oath-toolkit 存在漏洞的 usersfile commit
- oath-toolkit 上游私有问题
- SUSE 改进的错误修复
- SUSE 初始错误修复(旧版本)
- oath-toolkit CVE-2024-47191 安全公告
8) 变更历史
| 2024-10-21 | 添加了一个部分,讨论了原始 SUSE 补丁的不足之处,并提供了指向改进补丁的链接。 |