Print document Edit on github

原视频中,漏洞发现人[@Kevin Backhouse]简单介绍漏洞原理后对漏洞进行手动复现;而我们需注意的是:

  • 相关脚本1
    • 用法:bash polkit-CVE-2021-3560.sh username passwd

*Tips:详细视频可点击原视频链接观看,或者:

BiliBili - CVE-2021-3560 Linux提权漏洞复现2

尽管用作者的话来说是The vulnerability enables an unprivileged local user to get a root shell on the system. It’s easy to exploit with a few standard command line tools

而对于漏洞复现本身而言,我们似乎并不能百分百触发漏洞如果我们没有找到窍门,正如作者说的:

  • I like to think that it’s theoretically possible to trigger by smashing Ctrl+C at just the right moment, but I’ve never succeeded, so I do it with a small amount of bash scripting instead.

  • You might need to run that a few times, and you might need to experiment with the number of milliseconds in the delay

所以有了本文。


漏洞简介

该漏洞存在于系统服务Polkit中,因为Polkit被Systemd所调用,因此默认安装了Systemd的发行版都会使用Polkit;

该漏洞成因是执行dbus-send命令后在认证完成前强制终止引发错误,而Polkit未正确处理错误导致允许无特权的用户添加一个sudo用户。

dbus & polkit 交互流程图

[ *Tips:来源图见下方参考 ]3

polkit-diagram-cropped.png

虚线上方的两个进程——dbus-send 和Auth Agent是非特权用户进程。线下的那些是特权系统进程。中间是 dbus-daemon,它处理所有的通信:其他四个进程通过发送 D-Bus 消息来相互通信。

dbus-daemon 在 polkit 的安全性中扮演着非常重要的角色,因为它使四个进程能够安全地通信并检查彼此的凭据。

例如,当Auth Agent向 polkit 发送身份验证 cookie 时,它会通过将其发送到 org.freedesktop.PolicyKit1 D-Bus 地址来实现。由于该地址仅允许由根进程注册,因此不存在非特权进程拦截消息的风险。

我们从左边箭头指向方向到右边一个凹字形来看流程:4

  • dbus-send 命令行后台请求 dbus-daemon守护程序然后转发告诉 account-daemondbus-send程序请求
  • account-daemon守护程序收到请求返回确认字给dbus-daemon,同时告知polkit(我们的主角)
    • account-daemon 从 dbus-send 接收 D-Bus 消息,该消息包括发送者的唯一总线名称。
  • polkit返回dbus-daemon守护程序确认请求,最终到达Auth Agent认证端
    • polkit向dbus-daemon 询问连接的 UID
    • 如果连接的UID为’0’,则 polkit 立即授权该请求。 否则,它会向身份验证代理发送允许授权请求的管理员用户列表。
    • 身份验证代理打开一个对话框以从用户那里获取密码。
    • 身份验证代理将密码发送给 polkit,polkit 将“是”回复发送回帐户守护程序,account-daemon 创建新的用户帐户。

显而易见:问题流程在最后一段,我们通过漏洞发现者博客已知关键在于Kill掉dbus-send 命令导致了身份验证绕过,为什么?换而言之,漏洞出现在第三步骤的第二小步,挖掘思路是什么?

在此之前我们简单了解一下polkit,我认为可以把它想像成sudo认证机制的可视化界面,当我们的当前操作需要更多权限时那么就会触发polkit的认证机制:pkexec

$ pkexec id
==== AUTHENTICATING FOR org.freedesktop.policykit.exec ===
Authentication is needed to run `/usr/bin/id' as the super user
Authenticating as: bin4xin,,, (ingeek)
Password: 
polkit-agent-abouter-1: error response to PolicyKit daemon: GDBus.Error:org.freedesktop.PolicyKit1.Error.Failed: No session for cookie
==== AUTHENTICATION FAILED ===
Error executing command as another user: Not authorized

This incident has been reported.

# pkexec whoami
root

作者提到:在第三步骤的第一小步中询问dbus-daemon的函数 中代码存疑:

static gboolean
polkit_system_bus_name_get_creds_sync (
PolkitSystemBusName           *system_bus_name,
    guint32                       *out_uid,
    guint32                       *out_pid,
    GCancellable                  *cancellable,
    GError                       **error)

具体的代码分析可以参考原博客,我们这里就不做不过多的搬运和翻译。

所以如上我们可以得到的是polkit在询问dbus-daemon过程中未进行错误检查,导致在运行质询的过程中可以通过一些可控手段绕过认证机制:

The bug is in this snippet of code in check_authorization_sync: Notice that the value of error is not checked.

Poc代码需解决的如下:

  • 重复运行payload,函数检测是否添加用户payload是否成功;
  • 修改payload,计算kill polkit进程的时间;
  • 输出添加成功帐号密码。

Poc代码

  • 实验环境
    • Ubuntu 20.04
ingeek@ubuntu:~$ /etc/init.d/dbus status
● dbus.service - D-Bus System Message Bus
     Loaded: loaded (/lib/systemd/system/dbus.service; static; vendor preset: enabled)
     Active: active (running) since Tue 2021-06-15 23:00:47 PDT; 1h 26min ago
TriggeredBy: ● dbus.socket
       Docs: man:dbus-daemon(1)
   Main PID: 875 (dbus-daemon)
      Tasks: 1 (limit: 4618)
     Memory: 5.4M
     CGroup: /system.slice/dbus.service
             └─875 /usr/bin/dbus-daemon --system --address=systemd: --nofork --

参考

以上。