posted 2020-01-21
The Gentoo portage package manager builds packages in a temporary location. By default, that temporary location is accessible to unprivileged users even though the build essentially takes place as root. In some common situations (during reinstalls, for example), this leaves the source tree momentarily writable by an existing system user who can exploit the situation to gain root.
Portage is the default package manager on Gentoo Linux, a source-based
distribution. To install a package, portage runs through a series of
configuration, compilation, and installation phases consisting of
bash script. These all run with root privileges in a temporary
subdirectory of the location specified by the
PORTAGE_TMPDIR
variable. The install phase performs a
“mock” installation, in a self-contained directory, that
can be tweaked before proceeding to the next step. When the build
and mock-install are complete, the final result is merged onto the
live filesystem, again using root privileges.
Gentoo developers and portage itself take some care to ensure that
nothing objectionable reaches the live filesystem. Subdirectories of
PORTAGE_TMPDIR
, on the other hand, are the wild wild
west. Much of PORTAGE_TMPDIR
is world-traversable, and
that lack of access control turns out to be exploitable by users
who are granted ephemeral write access to the source tree of a
package being installed. If an unprivileged user can write to the
mock-installation image of a package, then in essence he can write
to the live filesystem as well because everything in the mock image
is merged onto the live filesystem eventually.
It is the nature of package maintenance that illicit things must take during the build and installation phases. For example, many upstream build systems set incorrect permissions on the files they produce, and those permissions must be corrected before the files are merged onto the system. But before problems are fixed in the mock-install, they exist in the mock-install. And many of them allow an unprivileged user to modify the source tree.
The nagioscore package is available in Gentoo as net-analyzer/nagios-core. By default its build system gives ownership of /usr/lib64/nagios/plugins to the nagios user, but this gets corrected to root:root to avoid surprises.
The two lines that accomplish that in the net-analyzer/nagios-core ebuild are,
The $D
variable refers to the mock-installation path
under PORTAGE_TMPDIR
, and
fowners implicitly acts there. But
between the call to emake and the call to
fowners, the plugin directory in the mock
installation image is writable by the nagios user. Below we
demonstrate how nagios can abuse this to install a
malicious plugin.
First, add a sleep
call to the ebuild to make it
easier to exploit interactively:
Install acct-user/nagios
once, so that the
unprivileged nagios is created on the system (in real
life, this happens automatically):
root # emerge -1 acct-user/nagios
Initiate an install of net-analyzer/nagios-core
:
root # emerge net-analyzer/nagios-core
When the ebuild reaches the sleep
call that we
added, the plugin directory in the mock-install image is
writable by the nagios user. Commandeer the
nagios user with su, and
place a malicious plugin there:
root # su -s /bin/sh nagios
nagios $ touch /var/tmp/portage/net-analyzer/nagios-core-*/image/usr/lib64/nagios/plugins/exploit.txt
Wait for the sleep()
to pass, and watch the
nagios-owned exploit be installed to the live system:
>>> /usr/lib64/nagios/cgi-bin/tac.cgi
>>> /usr/lib64/nagios/cgi-bin/extinfo.cgi
>>> /usr/lib64/nagios/cgi-bin/config.cgi
--- /usr/lib64/nagios/plugins/
>>> /usr/lib64/nagios/plugins/exploit.txt
Version 2.3.94 of portage now applies the stricter
PORTAGE_WORKDIR_MODE
permissions to the
PORTAGE_BUILDDIR
subdirectory of
PORTAGE_TMPDIR
. This prevents unprivileged users from
writing to the build directory.