CVE-2020-7468:FreeBSD ftpd chroot本地提权漏洞分析

漏洞概述

在今年7月,我们从一位匿名研究员那里收到了FreeBSD中的一个本地权限提升漏洞的相关信息,即一个存在于FreeBSD的文件传输协议守护进程( ftpd )中的漏洞。ftpd提供了一个名为 ftpchroot 的功能,旨在限制经过身份验证的用户对文件系统的访问。这个特性是使用“chroot”系统调用实现的,这是一种通常称为“chroot jail”的安全技术,chroot jail可以将进程限制在文件系统的受限部分来运行。但是,在该漏洞的帮助下,攻击者实际上可以利用这种被“囚禁”的状态来进行各种非法操作,将其权限从受限制的FTP帐户提升为“root”权限,并允许攻击者能够在目标系统上执行任意代码。此漏洞在FreeBSD FTP守护程序中存在了很长时间,最早可以追溯到FreeBSD 6.3版本。目前,这个漏洞被标记为了 CVE-2020-7468/ZDI-20-1431 ,相关 漏洞补丁 已于今年9月份正式发布。

漏洞分析

这个漏洞存在的根本原因是freebsd/libexec/ftpd/ftpd.c的chroot()函数在进行业务处理时存在设计缺陷。下面给出的是存在漏洞的函数简化版本:

void pass(char *passwd)

{

// ...

        if (guest || dochroot) {

// ...

                /*

                 * Finally, do chroot()

                 */

                if (chroot(chrootdir) pw_dir;

// ...

        if (chdir(homedir) < 0) {

                if (guest || dochroot) {

                        reply(550, "Can't change to base directory.");

                        goto bad;

                } else {

// ...

                }

// ...

bad:

        /* Forget all about it... */

#ifdef  LOGIN_CAP

        login_close(lc);

#endif

        if (residue)

                free(residue);

        end_login();

}

如果 FTP 用户试图登录并被配置为限制在/etc/ftpchroot中的chroot jail,那么ftpd将调用chroot和chdir系统调用)。如果chdir系统调用失败,则代码将跳转到标签bad处。在这种情况下,ftpd仍然会等待新的登录,但连接已锁定在chroot jail内。此时,将导致连接上的下次登录尝试会引发错误行为。

漏洞利用

为了强制chdir系统调用在登录过程中失效,攻击者可使用命令 chmod 0 在主目录上更改权限。另外,攻击者将会上传和主页目录相关的文件“etc/spwd.db”。该文件是修改过的常规 FreeBSD 系统(包含root用户的已知密码)的密码数据库。chdir调用失败后,ftpd会被锁定在chroot jail中,以便所有后续的文件系统访问都会跟用户主目录相关,而不是真实的文件系统root路径。这样一来,当对后续登录进行认证时,ftpd读取攻击者的spwd.db而不是存储在文件系统真实root目录下的/etc/spwd.db。此时,攻击者就可以通过已知密码以root身份进行登录了。

下一步,攻击者需要上传/etc/pam.d/ftpd和/usr/lib/pam_opie.so.5。第一个文件可以让ftpd在登录过程中加载多个动态库,其中就包括这第二个文件。第二个文件旨在通过已获得的root权限来突破chroot jail并执行反向Shell。接下来,攻击者就能够以root权限来执行任意代码了。

漏洞利用步骤大致如下:

  • 通过受限的 FTP 账户登录。
  • 上传包含已知root密码的etc/spwd.db。
  • 执行“chmod 0”。
  • 再次以受限的 FTP 账户登录。在登录过程中,chdir执行失败,导致ftpd进程在chroot jail中被锁定。
  • 通过已知密码以 root 身份登录。
  • 上传/etc/pam.d/ftpd和/usr/lib/pam_opie.so.5,后者包含一个反向Shell。
  • 再次以受限 FTP 账户身份登录。和之前一样,chdir执行失败,导致ftpd进程在chroot jail中被锁定。
  • 通过已知密码以 root 身份登录。ftpd执行该反向Shell。

漏洞修复

为解决这个问题,FreeBSD对其功能实现代码进行了修改,如果chdir系统调用失败的话,则ftpd将会立刻断开连接:

void fatalerror(char *s)

{

        reply(451, "Error in server: %s", s);

        reply(221, "Closing connection due to server error.");

        dologout(0);

        /* NOTREACHED */

}

 

void pass(char *passwd)

{

// ...

        if (chdir(homedir) < 0) {

                if (guest || dochroot) {

                        fatalerror("Can't change to base directory.");

                } else {

//...

}

总结

这个漏洞是一个逻辑提权漏洞,因此它的稳定性非常强,这个漏洞跟九月份发布的FreeBSD 内核提权漏洞( CVE-2020-7460 )也是不一样的。