CVE-2026-96512(SudoTimeWarp)的复现与PoC脚本,其中调用者的TZ会偏移sudoers的NOTBEFORE/NOTAFTER时间窗口,并附带缓解措施检查。
sudo:调用者的 TZ 决定 NOTBEFORE/NOTAFTER
SudoTimeWarp(CVE-2026-96512)的复现材料。sudoers 规则中的 Date_Spec 时间戳若省略末尾的 Z,会被 mktime() 转换,而 mktime() 在每次调用时都会重新读取 getenv("TZ")。由于 sudo 是 setuid-root 程序,且调用者的 environ 会原封不动地跨越 execve(),因此非特权调用者可以自行选择其有效期窗口被评估时所使用的时区。
基础问题——TZ 会影响 NOTBEFORE/NOTAFTER——由 腾讯玄武实验室 XlabAI 团队、Atuin 自动化漏洞发现引擎以及 Guannan Wang、Zhanpeng Liu 和 Guancheng Li 私下报告,并在提交 db669167c(2026-03-14)中致谢。
SudoTimeWarp(CVE-2026-96512)的发现是:db669167c 并不完整。 该提交引入的防护覆盖了 glibc 的时区缓存——以及随之而来的日志时间戳——但并未触及 gentime.c:156 处的 mktime(),而授权决策正是在那里做出的。在已包含该提交的代码树上,窗口偏移仍然完全可以复现。维护者在 1820a349 的提交信息中记录了这一点:
之前的更改“并未生效,因为 mktime() 函数在每次被调用时都会重新读取 TZ 环境变量”
一条 sudoers 规则需满足:(1) 向调用者授予某条命令,(2) 带有 NOTBEFORE= 或 NOTAFTER=,且 (3) 写入的时间戳不带 Z 后缀,也不带显式偏移量。
第 (3) 点并不罕见:sudoers 手册将无后缀形式记录为受支持的扩展,并打印 20151201235900 作为其四个示例时间戳之一(docs/sudoers.man.in:1820),而且该形式也出现在项目自身的回归测试语料中(plugins/sudoers/regress/testsudoers/test13.sh)。
务必在一次性容器或虚拟机中运行。 这里的每个脚本都会重写 /etc/sudoers。它们会先备份再恢复,但一旦出错,在真实机器上就会把你锁在外面——除非传入 --i-know,否则脚本会拒绝在容器外运行。
docker build -t sudotimewarp .
docker run --rm -it sudotimewarp
或者不构建镜像:
docker run --rm -it -v "$PWD:/m" debian:trixie bash -c \
'apt-get update >/dev/null && apt-get install -y sudo >/dev/null && bash /m/poc.sh'
在受影响的构建上预期输出:
=== probes ===
rule valid, no TZ : uid=0(root) gid=0(root) groups=0(root)
rule expired, no TZ : sudo: a password is required
rule expired, TZ=UTC : sudo: a password is required
rule expired, TZ=XXX24 : uid=0(root) gid=0(root) groups=0(root)
expired + 'Z', TZ=XXX24 : sudo: a password is required
XXX 是任意的三字母时区缩写,24 是 POSIX 偏移量。不涉及任何文件,也不需要任何文件存在——可利用的通道仅是内联 POSIX 字符串。tzfile 形式(TZ=:/tmp/evil.tz 及其变体)在 setuid 下会被 glibc 的 __libc_enable_secure 防护拒绝,实测偏移量恰好为 0 秒,这正是它与 CVE-2014-9680 的区别所在。
第 1–3 行是对照组,它们很重要:解析错误会产生与漏洞相同的 ALLOW 结果。
poc.sh 在受影响时退出 0,未受影响时退出 1,对照组未成立时退出 2。
poc.sh 使用 NOPASSWD 以便非交互式运行。这并非该漏洞的条件。拆分脚本明确展示了权限边界——第 1 部分只做管理员合法会做的事,第 2 部分以非特权用户身份运行,且不使用任何形式的特权:
bash repro-admin.sh escalation # as root: writes the policy
su - poc -c 'bash /poc/repro-attacker.sh'
bash repro-admin.sh --cleanup
repro-admin.sh 接受四种场景:
对于需要密码的规则,调用者仍需通过 PAM 认证,密码错误仍会失败。这不是认证绕过——发生移动的是授权决策。
PR:L,而非 PR:N。TZ 值均被拒绝。C:L/I:N/A:N)。7.8 向量评分针对的是带日期的规则比调用者的永久访问权限更宽泛的情形。约 25 小时的界限适用于访问窗口,而非影响持续时间:在窗口内成功使用一次,就足以建立比该窗口更持久的持久化。
为每个 NOTBEFORE/NOTAFTER 时间戳追加 Z——这会强制走 timegm() 分支。
grep -rE 'NOT(BEFORE|AFTER)=' /etc/sudoers /etc/sudoers.d/
不要用 sudo -l 进行审计。它会通过 gmtime() 格式化每个 Date_Spec,并总是追加 Z(plugins/sudoers/display.c:229),因此写成 NOTAFTER=20260827221423 的规则会显示为 NOTAFTER=20260827221423Z。其输出恰好把起决定作用的细节规范化掉了。cvtsudoers 和 fmtsudoers 的行为相同。请直接读取 /etc/sudoers。
1820a349:https://github.com/sudo-project/sudo/commit/1820a349687522f51023d1ae5925125f59679a8c于 2026-08-28 报告给维护者,未设截止期限。候选补丁当天即返回;公开修复于 2026-08-29 落地。CVE 由 Red Hat 以 CNA-LR 身份分配,并于 2026-09-23 发布。没有禁运期:自修复提交以来,这里的一切都已公开。
SudoTimeWarp / CVE-2026-96512:Ermenson Junior,独立研究,被 Red Hat 记录为“Independent security research”。底层问题的原始报告归功于腾讯玄武实验室 XlabAI 团队、Atuin 自动化漏洞发现引擎,以及 Guannan Wang、Zhanpeng Liu 和 Guancheng Li。
为防御用途发布:验证主机是否受影响,以及验证 Z 缓解措施。
| 名称 | SudoTimeWarp |
| CVE | CVE-2026-96512 |
| CVSS v3.1 | AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H — 7.8 High |
| CWE | CWE-863(已登记);机制为 CWE-807 |
| 受影响版本 | sudo 1.8.20 至 1.9.17p2,以及 1820a349 之前的 main |
| 修复于 | 1820a349(2026-08-29) |
| 偏移量 | 每个方向最多 24 小时 59 分 59 秒;总区间 49 小时 59 分 58 秒 |
| 行 | 检查内容 |
|---|
| 1 | 该规则在其窗口内确实有效 |
| 2 | 第 4 行缺失时的拒绝确实来自 NOTAFTER |
| 3 | 设置 TZ 本身并非原因——TZ=UTC 的判定与不设 TZ 相同 |
| 4 | 漏洞:已过期的规则以 root 身份执行 |
| 5 | 边界:使用文档所述的 Z 时,会走 timegm() 分支并失败 |
| 场景 | 策略 |
|---|
expired(默认) | 一条规则,NOTAFTER 为一小时前,无时区 |
valid | 同一规则仍在其窗口内——对照组 |
expired-z | 同一过期规则但带文档所述的 Z——对照组,不受影响的形式 |
escalation | 一条狭窄的永久授权加一条已过期的宽泛授权——维护或应急授权实际呈现的形态 |