如何在Ubuntu v20.04上获取root权限

 

写在前面的话

我个人非常喜欢Ubuntu,所以我也想尽自己所能让它变得更加安全。这段时间,我已知在寻找Ubuntu系统服务中得安全漏洞,我也发现并报告了一些问题,但大多数漏洞的严重性都很低。Ubuntu是开源的,这意味着已经有很多前辈已经看过它的源代码了,似乎所有的漏洞都已经被发现了。不过,我还是发现了一个问题,并打算在这篇文章中跟大家详细介绍一下。

在这篇文章中,我将跟大家介绍一种在Ubuntu上实现权限提升的方法。只需要在命令行终端中输入几个简单的命令,再点击几次鼠标,普通权限的用户就可以为自己创建一个管理员账户了。在文章中,我还提供了一个演示视频以供大家学习参考。

注意,这个漏洞只会影响使用图形化系统桌面的Ubuntu用户。

 

漏洞利用步骤

首先,我们需要打开一个命令行窗口,然后创建一个指向home目录的符号链接:

ln -s /dev/zero .pam_environment

如果这个命令运行不了的话,可能是因为目标目录下已经存在一个名为.pam_environment的文件了,我们可以把这个旧文件重命名一下,等需要用到的时候再恢复就行了。

接下来,在系统设置中打开“区域&语言”选项,然后尝试修改语言。此时对话框将会卡住,这里大家不用管,此时切换回终端窗口。这个时候,一个名为accounts-daemon的程序将会占用100%的CPU资源,此时你的电脑将会变得非常卡。

不要慌,在命令行中删除这个符号链接,否则你可能会把自己锁定在自己的账号里:

crm .pam_environment

下一步,给accounts-daemon发送一个SIGSTOP信号,让它停止占用CPU资源。但是这里,我们首先需要知道accounts-daemon的进程标识符(PID)。在演示视频中,我使用的是top工具(用于监控运行进程),因为accounts-daemon已经陷入了一个死循环中,这样可以让它立刻排到列表顶部。另一个寻找PID的方法就是使用pidof工具:

$ pidof accounts-daemon
597

拿到accounts-daemon的进程标识符(PID)之后,我们就可以使用kill命令来发送SIGSTOP信号了:

kill -SIGSTOP 597

现在,你的电脑应该能“喘过气”了吧。

接下来就是关键步骤了!现在,注销你的账号,但你得先设置一个定时器来在你注销账号之后重启accounts-daemon进程。否则,你将被锁定无法登录,那么漏洞利用也就失败了。设置定时器的代码如下:

nohup bash -c "sleep 30s; kill -SIGSEGV 597; kill -SIGCONT 597"

nohup工具可以让我们注销之后仍然保持脚本的运行状态,这个命令将运行一个bash脚本,这个脚本会做三件事情:

1、休眠30秒;

2、给accounts-daemon发送一个SIGSEGV信号,来让程序崩溃亏;

3、给accounts-daemon发送一个SIGCONT信号来停用之前发送的SIGSTOP。SIGSEGV不会生效,直到接收到了SIGCONT为止;

完成之后,注销账号,然后等几秒种让SIGSEGV执行。如果漏洞利用成功,你将会看到一大堆的对话框弹出来,然后帮助你设置一个新的用户账号,而这个新账号,就是管理员账号。

 

漏洞运行机制

不用担心,就算你之前对Ubuntu(准确的说应该是GNOME)不是非常了解,我也会耐心跟大家介绍这个漏洞的。实际上,这里涉及到两个漏洞,第一个漏洞存在于accountsservice中,这个服务负责管理计算机上的用户账号。第二个漏洞存在于GNOME Display Manager (gdm3)中,它负责管理登录界面。

accountsservice拒绝服务漏洞(GHSL-2020-187、GHSL-2020-188/CVE-2020-16126、CVE-2020-16127)

accountsservice守护进程(accounts-daemon)是一个负责管理设备上用户账号的系统服务。它可以创建新的用户账号,或修改用户密码。除此之外,它还能修改用户的头像或语言偏好。守护进程能够在系统后台运行,而且不需要拥有用户接口。但是,系统设置对话框能够通过D-Bus这个消息系统来跟accounts-daemon交互:

 

关于D-Bus

D-Bus实质上一个适用于桌面应用的进程间的通讯机制,即所谓的IPC(inter-process communication)机制。它最初产生于Linux平台,是做为freedesktop.org项目的一部分来开发的。现在已经深入地渗透到 Linux 桌面之中。在Qt4,GNOME,Windows以及Maemo中都已实现。在KDE4中已经取代了著名的DCOP,在GNOME取代笨重的Bonobo。在嵌入式系统中常用来实现C/S结构。

D-Bus 作为应用程序间通信的消息总线系统, 用于进程之间的通信。它是个3层架构的IPC 系统,包括:

1、函数库libdbus,用于两个应用程序互相联系和交互消息。

2、一个基于libdbus构造的消息总线守护进程,可同时与多个应用程序相连,并能把来自一个应用程序的消息路由到0或者多个其他程序。

3、基于特定应用程序框架的封装库或捆绑(wrapper libraries or bindings )。

例如,libdbus-glib和libdbus-qt,还有绑定在其他语言,例如Python的。大多数开发者都是使用这些封装库的API,因为它们简化了D-Bus编程细节。libdbus被有意设计成为更高层次绑定的底层后端(low-level backend )。大部分libdbus的 API仅仅是为了用来实现绑定。

 

继续我们的漏洞利用分析

在漏洞利用过程中,我使用了系统设置对话框来修改语言。标准用户可以自己修改这个设置,而无需管理员权限。在后台,系统服务对话框此时会通过D-Bus向accounts-daemon发送org.freedesktop.Accounts.User.SetLanguage命令。
实际上,Ubuntu使用的是一个修改版的accountsservice,其中包含了freedesktop上游版本中未包含的额外代码。Ubuntu添加了一个名为is_in_pam_environment的函数,它会寻找并读取用户home目录下一个名为.pam_environment的文件。此时,我们只需要制作一个.pam_environment指向/dev/zero的符号链接,即可触发这个拒绝服务漏洞。/dev/zero是一个特殊的文件,它实际上并不存在于磁盘中。它由操作系统提供,全部由零字节组成。当is_in_pam_environment尝试读取.pam_environment时,它会被符号链接重定向到/dev/zero,然后陷入无限循环中。

accounts-daemon的无响应触发的gdm3提权漏洞(GHSL-2020-202 / CVE-2020-16125)

GNOME Display Manager(gdm3)是Ubuntu用户接口中的一个基础组件,它负责处理用户在登录和注销过程中的类似用户会话启动和关闭之类的任务。除此之外,它还负责管理系统的登录界面。

gdm3负责处理的另一个东西就是计算机在安装完新系统之后的初始化配置,当你在一台新的设备上安装好Ubuntu之后,第一件要做的事情就是创建一个新的用户账号。初始用户账号需要是一个管理员账号,这样我们才能继续完成设备的配置,比如说配置WiFi和安装应用程序等等。下面给出的截图显示的就是设备的初始化安装界面:

大家在上图中看到的对话框就是一个单独的应用程序,这个应用程序名叫gnome-initial-setup,当系统中不存在用户账号时,gdm3便会触发它的执行,也就是在系统初始化配置的时候会执行。

它会使用D-Bus来询问accounts-daemon:现在系统中已经有多少个用户账号了?但是由于accounts-daemon已经无响应了,那么D-Bus的调用也就因超时(大约20秒超时时间)而失败了。由于超时情况的出现,代码并不会设置priv->have_existing_user_accounts的值。不幸的是,priv->have_existing_user_accounts的默认值为false,而不是true。那么现在,gdm3将认为系统中不存在任何用户账号,于是它便会启动gnome-initial-setup。

没错,就是这么简单!

(完)