authorized_key 本地权限提升通过跟随符号链接的 chown(以及跟随符号链接的文件创建)对用户的 ~/.ssh 目录和 authorized_keys 文件,在 ansible.posix.authorized_key Ansible 模块中实现本地权限提升。
这是一份关于我报告的漏洞的书面说明,该漏洞已被红帽产品安全团队(CNA)分配为 CVE-2026-11837。此处作为技术记录发布,而非声称具有新颖性:该问题是 CVE-2024-9902 的 同源问题,早期修复未覆盖到该模块。
红帽发布的致谢:“红帽感谢 Valentino Paulon 报告此问题。”
| CVE | CVE-2026-11837 |
| 组件 | ansible.posix 集合,文件 plugins/modules/authorized_key.py,函数 keyfile() |
| 类型 | 本地权限提升(本地)。CWE-59 / CWE-61(链接跟随)结合 CWE-282(不当所有权管理) |
| CVSS | 7.3(高危) |
| 公开日期 | 2026-06-10 |
| 报告者 | Valentino Paulon |
当一个以 root 身份运行的 playbook 使用 ansible.posix.authorized_key 管理本地用户的密钥时,模块的 keyfile() 辅助函数:
os.chown(而非 os.lchown)更改用户 ~/.ssh 目录和 ~/.ssh/authorized_keys 文件的所有权;open(..., "w")(不带 O_NOFOLLOW)创建密钥文件。使用默认的 follow=False,模块既不会跟随并替换符号链接,也不会拒绝符号链接;它直接对路径进行操作,因此内核会跟随非特权目标用户在其自己的 ~/.ssh 中预先放置的任何符号链接。这提供了两种基元,可将 root 控制的路径的所有权转移给非特权用户,然后该用户提升至 root。两种方法均已在针对集合的 HEAD 版本上端到端复现。
keyfile()(plugins/modules/authorized_key.py),使用默认的 manage_dir=True,follow=False:
if manage_dir:
if not os.path.exists(sshdir): # os.path.exists 跟随符号链接
try:
os.mkdir(sshdir, int('0700', 8))
...
os.chown(sshdir, uid, gid) # 无条件,普通的 chown,跟随符号链接
os.chmod(sshdir, int('0700', 8)) # 跟随符号链接
if not os.path.exists(keysfile): # 跟随符号链接
...
f = open(keysfile, "w") # 普通的 open(),不带 O_NOFOLLOW,跟随符号链接
...
try:
os.chown(keysfile, uid, gid) # 无条件,普通的 chown,跟随符号链接
os.chmod(keysfile, int('0600', 8)) # 跟随符号链接
except OSError:
pass
sshdir 和 keysfile 源自目标用户的 passwd 家目录(pwd.getpwnam(user).pw_dir),这是一个非特权目标用户拥有并控制的目录。follow 参数(默认为 False)仅决定是否对路径调用 os.path.realpath();两种情况下均无 os.path.islink 检查、O_NOFOLLOW 打开、os.lchown 或对预先存在的符号链接进行取消链接并替换操作。未执行权限降级(seteuid/setfsuid);一切以 root 身份运行。
两个 os.chown 调用无条件执行,位于 if not os.path.exists(...) 守卫之外,因此无论目录/文件是否已经存在,它们都会触发。这正是两种基元可靠的原因。
两种方法均已在一次性的 Linux 虚拟机上使用 ansible.posix 的 HEAD 版本端到端确认。victim 是一个非特权本地用户(uid 1000)。模块以 root 身份运行,正如操作员的 playbook 通常所做的那样。Canary 文件代表敏感的目标 root 路径。
向量 1:目录符号链接(对现有 root 拥有的目录执行 chown)
victim 身份:ln -s /root/AD_CANARY ~/.ssh(其中 /root/AD_CANARY 是一个已有的 root 拥有的目录)。victim 运行 authorized_key 任务。/root/AD_CANARY 的所有权从 root:root 变为 victim:victim。os.chown(sshdir, ...) 调用跟随了 ~/.ssh 符号链接,并将一个 root 拥有的目录交给了非特权用户。向量 2:悬空文件符号链接(创建并 chown 一个新的 root 路径文件)
victim 身份(~/.ssh 是一个普通目录):ln -s /root/AF_CANARY ~/.ssh/authorized_keys(目标不存在)。victim 运行 authorized_key 任务。/root/AF_CANARY 被创建,所有者 victim:victim,权限 0600。open(keysfile, "w") 通过符号链接创建了目标文件,而 os.chown(keysfile, ...) 将所有权移交。在这两种情况下,非特权用户最终都拥有了一个 root 控制的路径。将链接指向 /etc 下的一个目录(向量 1),或指向 /etc/cron.d/ 或 /etc/sudoers.d/ 下的一个新文件(向量 2),通过标准的后续操作即可获得 root 权限——用户(现在是所有者)会重写目标。
这是 CVE-2024-9902(ansible-core 中 user 模块的 generate_ssh_key,解决了同一类符号链接跟随问题)的同源问题。authorized_key 位于独立的 ansible.posix 集合中,并未因该修复而改变;符号链接跟随的 chown/创建模式仍然存在且未受保护。它作为同一已被接受的类别在先前修复未触及的模块中报告,而非一种新的根本原因。
ansible.posix.authorized_key 任务(该模块的常见用法)。本地用户在其自己的 ~/.ssh 中预先放置符号链接;他们并不运行 playbook。这是由操作员触发的:与 CVE-2024-9902 相同的触发模型,红帽接受其缓解措施为“不要针对不受信任的账户运行”。该先决条件被明确陈述,而非评为自触发。os.open(keysfile, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, 0o600) 并对描述符进行操作;如果 sshdir 或 keysfile 是符号链接,则拒绝(或根据 follow=False 的文档字符串约定取消链接并替换)。os.chown(...) 替换为 os.lchown,或替换为在安全打开的描述符上使用 os.fchown,同样使用 os.fchmod 代替 os.chmod,这样所有者和权限无法通过链接重定向。chown/chmod 添加守卫,使其仅应用于模块本身安全创建的新路径,而不是应用于预先存在的(可能是符号链接的)路径。| 日期 | 事件 |
|---|---|
| 2026年6月8日 | 报告至 [email protected](同时抄送红帽产品安全团队作为 CNA),框架为 CVE-2024-9902 的同源问题 |
| 2026年6月10日 | CVE-2026-11837 分配并发布;致谢已接受 |
MIT。参见 LICENSE。